1#! /usr/bin/perl 2# ex:ts=8 sw=4: 3# $OpenBSD: Signer.pm,v 1.6 2015/01/04 14:10:20 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; 26 27my $h = { 28 x509 => 'OpenBSD::Signer::X509', 29 signify => 'OpenBSD::Signer::SIGNIFY', 30}; 31 32sub factory 33{ 34 my ($class, $state) = @_; 35 36 my @p = @{$state->{signature_params}}; 37 38 if (defined $h->{$p[0]}) { 39 return $h->{$p[0]}->new($state, @p); 40 } else { 41 $state->usage("Unknown signature scheme $p[0]"); 42 } 43} 44 45package OpenBSD::Signer::X509; 46sub new 47{ 48 my ($class, $state, @p) = @_; 49 50 if (@p != 3 || !-f $p[1] || !-f $p[2]) { 51 $state->usage("$p[0] signature wants -s cert -s privkey"); 52 } 53 bless {cert => $p[1], privkey => $p[2]}, $class; 54} 55 56sub new_sig 57{ 58 require OpenBSD::x509; 59 return OpenBSD::PackingElement::DigitalSignature->blank('x509'); 60} 61 62sub compute_signature 63{ 64 my ($self, $state, $plist) = @_; 65 return OpenBSD::x509::compute_signature($plist, $self->{cert}, 66 $self->{privkey}); 67} 68 69package OpenBSD::Signer::SIGNIFY; 70sub new 71{ 72 my ($class, $state, @p) = @_; 73 if (@p != 2 || !-f $p[1]) { 74 $state->usage("$p[0] signature wants -s privkey"); 75 } 76 my $o = bless {privkey => $p[1]}, $class; 77 my $signer = $o->{privkey}; 78 $signer =~ s/\.sec$//; 79 my $pubkey = "$signer.pub"; 80 $signer =~ s,.*/,,; 81 $o->{signer} = $signer; 82 if (!-f $pubkey) { 83 $pubkey =~ s,.*/,/etc/signify/,; 84 if (!-f $pubkey) { 85 $state->errsay("warning: public key not found"); 86 return $o; 87 } 88 } 89 $o->{pubkey} = $pubkey; 90 return $o; 91} 92 93sub new_sig 94{ 95 require OpenBSD::signify; 96 return OpenBSD::PackingElement::DigitalSignature->blank('signify'); 97} 98 99sub compute_signature 100{ 101 my ($self, $state, $plist) = @_; 102 103 OpenBSD::PackingElement::Signer->add($plist, $self->{signer}); 104 105 return OpenBSD::signify::compute_signature($plist, $state, 106 $self->{privkey}, $self->{pubkey}); 107} 108 109# specific parameter handling plus element creation 110package OpenBSD::CreateSign::State; 111our @ISA = qw(OpenBSD::AddCreateDelete::State); 112 113sub handle_options 114{ 115 my ($state, $opt_string, @usage) = @_; 116 $state->{opt}{s} = 117 sub { 118 push(@{$state->{signature_params}}, shift); 119 }; 120 $state->{no_exports} = 1; 121 $state->SUPER::handle_options($opt_string.'s:', @usage); 122 if (defined $state->{signature_params}) { 123 $state->{signer} = OpenBSD::Signer->factory($state); 124 } 125} 126 127sub create_archive 128{ 129 my ($state, $filename, $dir) = @_; 130 require IO::Compress::Gzip; 131 my $level = $state->{subst}->value('COMPRESSION_LEVEL') // 6; 132 my $fh = IO::Compress::Gzip->new($filename, 133 -Level => $level, -Time => 0) or 134 $state->fatal("Can't create archive #1: #2", $filename, $!); 135 $state->{archive_filename} = $filename; 136 return OpenBSD::Ustar->new($fh, $state, $dir); 137} 138 139sub new_gstream 140{ 141 my $state = shift; 142 close($state->{archive}{fh}); 143 my $level = $state->{subst}->value('COMPRESSION_LEVEL') // 6; 144 $state->{archive}{fh} =IO::Compress::Gzip->new( 145 $state->{archive_filename}, 146 -Level => $level, -Time => 0, -Append => 1) or 147 $state->fatal("Can't append to archive #1: #2", 148 $state->{archive_filename}, $!); 149} 150 151sub add_signature 152{ 153 my ($state, $plist) = @_; 154 155 if ($plist->has('digital-signature') || $plist->has('signer')) { 156 if ($state->defines('resign')) { 157 if ($state->defines('nosig')) { 158 $state->errsay("NOT CHECKING DIGITAL SIGNATURE FOR #1", 159 $plist->pkgname); 160 } else { 161 if (!$plist->check_signature($state)) { 162 $state->fatal("#1 is corrupted", 163 $plist->pkgname); 164 } 165 } 166 $state->errsay("Resigning #1", $plist->pkgname); 167 delete $plist->{'digital-signature'}; 168 delete $plist->{signer}; 169 } 170 } 171 172 my $sig = $state->{signer}->new_sig; 173 $sig->add_object($plist); 174 $sig->{b64sig} = $state->{signer}->compute_signature($state, $plist); 175} 176 177sub ntodo 178{ 179 my ($self, $offset) = @_; 180 return sprintf("%u/%u", $self->{done}-$offset, $self->{total}); 181} 182 1831; 184