1
2#	pre-5.14.0 perl inadvertently destroys signal handlers
3#	http://rt.perl.org/rt3/Public/Bug/Display.html?id=76138
4use strict;
5use warnings;
6local %SIG;
7
8
9package Net::DNS::RR::SIG;
10
11use strict;
12use warnings;
13our $VERSION = (qw$Id: SIG.pm 1819 2020-10-19 08:07:24Z willem $)[2];
14
15use base qw(Net::DNS::RR);
16
17
18=head1 NAME
19
20Net::DNS::RR::SIG - DNS SIG resource record
21
22=cut
23
24use integer;
25
26use Carp;
27use Time::Local;
28
29use Net::DNS::Parameters qw(:type);
30
31use constant DEBUG => 0;
32
33use constant UTIL => defined eval { require Scalar::Util; };
34
35eval { require MIME::Base64 };
36
37# IMPORTANT: Downstream distros MUST NOT create dependencies on Net::DNS::SEC	(strong crypto prohibited in many territories)
38use constant USESEC => defined $INC{'Net/DNS/SEC.pm'};		# Discover how we got here, without exposing any crypto
39								# Discourage static code analysers and casual greppers
40use constant DNSSEC => USESEC && defined eval join '', qw(r e q u i r e), ' Net::DNS', qw(:: SEC :: Private);	## no critic
41
42my @index;
43if (DNSSEC) {
44	my $key = Net::DNS::RR->new( type => 'DNSKEY', key => 'AwEAAQ==' );
45	foreach my $class ( map {"Net::DNS::SEC::$_"} qw(RSA DSA ECCGOST ECDSA EdDSA) ) {
46		my @algorithms = eval join '', qw(r e q u i r e), " $class; $class->_index";	## no critic
47		@algorithms = grep { eval { $key->algorithm($_); $class->verify( '', $key, '' ); 1 } } ( 1 .. 16 )
48				unless scalar(@algorithms);	# Grotesquely inefficient; but need to support pre-1.14 API
49		push @index, map { ( $_ => $class ) } @algorithms;
50	}
51}
52
53my %DNSSEC_verify = @index;
54my %DNSSEC_siggen = @index;
55
56my @field = qw(typecovered algorithm labels orgttl sigexpiration siginception keytag);
57
58
59sub _decode_rdata {			## decode rdata from wire-format octet string
60	my $self = shift;
61	my ( $data, $offset, @opaque ) = @_;
62
63	my $limit = $offset + $self->{rdlength};
64	@{$self}{@field} = unpack "\@$offset n C2 N3 n", $$data;
65	( $self->{signame}, $offset ) = Net::DNS::DomainName2535->decode( $data, $offset + 18 );
66	$self->{sigbin} = substr $$data, $offset, $limit - $offset;
67
68	croak('misplaced or corrupt SIG') unless $limit == length $$data;
69	my $raw = substr $$data, 0, $self->{offset};
70	$self->{rawref} = \$raw;
71	return;
72}
73
74
75sub _encode_rdata {			## encode rdata as wire-format octet string
76	my $self = shift;
77	my ( $offset, @opaque ) = @_;
78
79	my ( $hash, $packet ) = @opaque;
80
81	my $signame = $self->{signame};
82
83	if ( DNSSEC && !$self->{sigbin} ) {
84		my $private = delete $self->{private};		# one shot is all you get
85		my $sigdata = $self->_CreateSigData($packet);
86		$self->_CreateSig( $sigdata, $private || die 'missing key reference' );
87	}
88
89	return pack 'n C2 N3 n a* a*', @{$self}{@field}, $signame->encode, $self->sigbin;
90}
91
92
93sub _format_rdata {			## format rdata portion of RR string.
94	my $self = shift;
95
96	my $sname = $self->{signame} || return '';
97	my @sig64 = split /\s+/, MIME::Base64::encode( $self->sigbin );
98	my @rdata = ( map( { $self->$_ } @field ), $sname->string, @sig64 );
99	return @rdata;
100}
101
102
103sub _parse_rdata {			## populate RR from rdata in argument list
104	my $self = shift;
105
106	foreach ( @field, qw(signame) ) { $self->$_(shift) }
107	$self->signature(@_);
108	return;
109}
110
111
112sub _defaults {				## specify RR attribute default values
113	my $self = shift;
114
115	$self->class('ANY');
116	$self->typecovered('TYPE0');
117	$self->algorithm(1);
118	$self->labels(0);
119	$self->orgttl(0);
120	$self->sigval(10);
121	return;
122}
123
124
125#
126# source: http://www.iana.org/assignments/dns-sec-alg-numbers
127#
128{
129	my @algbyname = (
130		'DELETE'	     => 0,			# [RFC4034][RFC4398][RFC8078]
131		'RSAMD5'	     => 1,			# [RFC3110][RFC4034]
132		'DH'		     => 2,			# [RFC2539]
133		'DSA'		     => 3,			# [RFC3755][RFC2536]
134					## Reserved	=> 4,	# [RFC6725]
135		'RSASHA1'	     => 5,			# [RFC3110][RFC4034]
136		'DSA-NSEC3-SHA1'     => 6,			# [RFC5155]
137		'RSASHA1-NSEC3-SHA1' => 7,			# [RFC5155]
138		'RSASHA256'	     => 8,			# [RFC5702]
139					## Reserved	=> 9,	# [RFC6725]
140		'RSASHA512'	     => 10,			# [RFC5702]
141					## Reserved	=> 11,	# [RFC6725]
142		'ECC-GOST'	     => 12,			# [RFC5933]
143		'ECDSAP256SHA256'    => 13,			# [RFC6605]
144		'ECDSAP384SHA384'    => 14,			# [RFC6605]
145		'ED25519'	     => 15,			# [RFC8080]
146		'ED448'		     => 16,			# [RFC8080]
147
148		'INDIRECT'   => 252,				# [RFC4034]
149		'PRIVATEDNS' => 253,				# [RFC4034]
150		'PRIVATEOID' => 254,				# [RFC4034]
151					## Reserved	=> 255,	# [RFC4034]
152		);
153
154	my %algbyval = reverse @algbyname;
155
156	foreach (@algbyname) { s/[\W_]//g; }			# strip non-alphanumerics
157	my @algrehash = map { /^\d/ ? ($_) x 3 : uc($_) } @algbyname;
158	my %algbyname = @algrehash;				# work around broken cperl
159
160	sub _algbyname {
161		my $arg = shift;
162		my $key = uc $arg;				# synthetic key
163		$key =~ s/[\W_]//g;				# strip non-alphanumerics
164		my $val = $algbyname{$key};
165		return $val if defined $val;
166		return $key =~ /^\d/ ? $arg : croak qq[unknown algorithm "$arg"];
167	}
168
169	sub _algbyval {
170		my $value = shift;
171		return $algbyval{$value} || return $value;
172	}
173}
174
175
176my %siglen = (
177	1  => 128,
178	3  => 41,
179	5  => 256,
180	6  => 41,
181	7  => 256,
182	8  => 256,
183	10 => 256,
184	12 => 64,
185	13 => 64,
186	14 => 96,
187	15 => 64,
188	16 => 114,
189	);
190
191
192sub _size {				## estimate encoded size
193	my $self  = shift;
194	my $clone = bless {%$self}, ref($self);			# shallow clone
195	$clone->sigbin( 'x' x $siglen{$self->algorithm} );
196	return length $clone->encode();
197}
198
199
200sub typecovered {
201	my $self = shift;					# uncoverable pod
202	$self->{typecovered} = typebyname(shift) if scalar @_;
203	my $typecode = $self->{typecovered};
204	return defined $typecode ? typebyval($typecode) : undef;
205}
206
207
208sub algorithm {
209	my ( $self, $arg ) = @_;
210
211	unless ( ref($self) ) {		## class method or simple function
212		my $argn = pop;
213		return $argn =~ /[^0-9]/ ? _algbyname($argn) : _algbyval($argn);
214	}
215
216	return $self->{algorithm} unless defined $arg;
217	return _algbyval( $self->{algorithm} ) if $arg =~ /MNEMONIC/i;
218	return $self->{algorithm} = _algbyname($arg);
219}
220
221
222sub labels {
223	return shift->{labels} = 0;				# uncoverable pod
224}
225
226
227sub orgttl {
228	return shift->{orgttl} = 0;				# uncoverable pod
229}
230
231
232sub sigexpiration {
233	my $self = shift;
234	$self->{sigexpiration} = _string2time(shift) if scalar @_;
235	my $time = $self->{sigexpiration};
236	return unless defined wantarray && defined $time;
237	return UTIL ? Scalar::Util::dualvar( $time, _time2string($time) ) : _time2string($time);
238}
239
240sub siginception {
241	my $self = shift;
242	$self->{siginception} = _string2time(shift) if scalar @_;
243	my $time = $self->{siginception};
244	return unless defined wantarray && defined $time;
245	return UTIL ? Scalar::Util::dualvar( $time, _time2string($time) ) : _time2string($time);
246}
247
248sub sigex { return &sigexpiration; }	## historical
249
250sub sigin { return &siginception; }	## historical
251
252sub sigval {
253	my $self = shift;
254	no integer;
255	( $self->{sigval} ) = map { int( 60.0 * $_ ) } @_;
256	return;
257}
258
259
260sub keytag {
261	my $self = shift;
262
263	$self->{keytag} = 0 + shift if scalar @_;
264	return $self->{keytag} || 0;
265}
266
267
268sub signame {
269	my $self = shift;
270
271	$self->{signame} = Net::DNS::DomainName2535->new(shift) if scalar @_;
272	return $self->{signame} ? $self->{signame}->name : undef;
273}
274
275
276sub sig {
277	my $self = shift;
278	return MIME::Base64::encode( $self->sigbin(), "" ) unless scalar @_;
279	return $self->sigbin( MIME::Base64::decode( join "", @_ ) );
280}
281
282
283sub sigbin {
284	my $self = shift;
285
286	$self->{sigbin} = shift if scalar @_;
287	return $self->{sigbin} || "";
288}
289
290
291sub signature { return &sig; }
292
293
294sub create {
295	unless (DNSSEC) {
296		croak qq[No "use Net::DNS::SEC" declaration in application code];
297	} else {
298		my ( $class, $data, $priv_key, %etc ) = @_;
299
300		my $private = ref($priv_key) ? $priv_key : Net::DNS::SEC::Private->new($priv_key);
301		croak 'Unable to parse private key' unless ref($private) eq 'Net::DNS::SEC::Private';
302
303		my $self = Net::DNS::RR->new(
304			type	     => 'SIG',
305			typecovered  => 'TYPE0',
306			siginception => time(),
307			algorithm    => $private->algorithm,
308			keytag	     => $private->keytag,
309			signame	     => $private->signame,
310			);
311
312		while ( my ( $attribute, $value ) = each %etc ) {
313			$self->$attribute($value);
314		}
315
316		$self->{sigexpiration} = $self->{siginception} + $self->{sigval}
317				unless $self->{sigexpiration};
318
319		$self->_CreateSig( $self->_CreateSigData($data), $private ) if $data;
320
321		$self->{private} = $private unless $data;	# mark packet for SIG0 generation
322		return $self;
323	}
324}
325
326
327sub verify {
328
329	# Reminder...
330
331	# $dataref may be either a data string or a reference to a
332	# Net::DNS::Packet object.
333	#
334	# $keyref is either a key object or a reference to an array
335	# of keys.
336
337	unless (DNSSEC) {
338		croak qq[No "use Net::DNS::SEC" declaration in application code];
339	} else {
340		my ( $self, $dataref, $keyref ) = @_;
341
342		if ( my $isa = ref($dataref) ) {
343			print '$dataref argument is ', $isa, "\n" if DEBUG;
344			croak '$dataref must be scalar or a Net::DNS::Packet'
345					unless $isa =~ /Net::DNS/ && $dataref->isa('Net::DNS::Packet');
346		}
347
348		print '$keyref argument is of class ', ref($keyref), "\n" if DEBUG;
349		if ( ref($keyref) eq "ARRAY" ) {
350
351			#  We will iterate over the supplied key list and
352			#  return when there is a successful verification.
353			#  If not, continue so that we survive key-id collision.
354
355			print "Iterating over ", scalar(@$keyref), " keys\n" if DEBUG;
356			my @error;
357			foreach my $keyrr (@$keyref) {
358				my $result = $self->verify( $dataref, $keyrr );
359				return $result if $result;
360				my $error = $self->{vrfyerrstr};
361				my $keyid = $keyrr->keytag;
362				push @error, "key $keyid: $error";
363				print "key $keyid: $error\n" if DEBUG;
364				next;
365			}
366
367			$self->{vrfyerrstr} = join "\n", @error;
368			return 0;
369
370		} elsif ( $keyref->isa('Net::DNS::RR::DNSKEY') ) {
371
372			print "Validating using key with keytag: ", $keyref->keytag, "\n" if DEBUG;
373
374		} else {
375			croak join ' ', ref($keyref), 'can not be used as SIG0 key';
376		}
377
378		croak "SIG typecovered is TYPE$self->{typecovered}" if $self->{typecovered};
379
380		if (DEBUG) {
381			print "\n ---------------------- SIG DEBUG ----------------------";
382			print "\n  SIG:\t", $self->string;
383			print "\n  KEY:\t", $keyref->string;
384			print "\n -------------------------------------------------------\n";
385		}
386
387		$self->{vrfyerrstr} = '';
388		unless ( $self->algorithm == $keyref->algorithm ) {
389			$self->{vrfyerrstr} = 'algorithm does not match';
390			return 0;
391		}
392
393		unless ( $self->keytag == $keyref->keytag ) {
394			$self->{vrfyerrstr} = 'keytag does not match';
395			return 0;
396		}
397
398		# The data that is to be verified
399		my $sigdata = $self->_CreateSigData($dataref);
400
401		my $verified = $self->_VerifySig( $sigdata, $keyref ) || return 0;
402
403		# time to do some time checking.
404		my $t = time;
405
406		if ( _ordered( $self->{sigexpiration}, $t ) ) {
407			$self->{vrfyerrstr} = join ' ', 'Signature expired at', $self->sigexpiration;
408			return 0;
409		} elsif ( _ordered( $t, $self->{siginception} ) ) {
410			$self->{vrfyerrstr} = join ' ', 'Signature valid from', $self->siginception;
411			return 0;
412		}
413
414		return 1;
415	}
416}								#END verify
417
418
419sub vrfyerrstr {
420	return shift->{vrfyerrstr};
421}
422
423
424########################################
425
426sub _CreateSigData {
427	if (DNSSEC) {
428		my ( $self, $message ) = @_;
429
430		if ( ref($message) ) {
431			die 'missing packet reference' unless $message->isa('Net::DNS::Packet');
432			my @unsigned = grep { ref($_) ne ref($self) } @{$message->{additional}};
433			local $message->{additional} = \@unsigned;    # remake header image
434			my @part = qw(question answer authority additional);
435			my @size = map { scalar @{$message->{$_}} } @part;
436			my $rref = delete $self->{rawref};
437			my $data = $rref ? $$rref : $message->data;
438			my ( $id, $status ) = unpack 'n2', $data;
439			my $hbin = pack 'n6 a*', $id, $status, @size;
440			$message = $hbin . substr $data, length $hbin;
441		}
442
443		my $sigdata = pack 'n C2 N3 n a*', @{$self}{@field}, $self->{signame}->encode;
444		print "\npreamble\t", unpack( 'H*', $sigdata ), "\nrawdata\t", unpack( 'H100', $message ), " ...\n"
445				if DEBUG;
446		return join '', $sigdata, $message;
447	}
448}
449
450
451########################################
452
453sub _CreateSig {
454	if (DNSSEC) {
455		my $self = shift;
456
457		my $algorithm = $self->algorithm;
458		my $class     = $DNSSEC_siggen{$algorithm};
459
460		return eval {
461			die "algorithm $algorithm not supported\n" unless $class;
462			$self->sigbin( $class->sign(@_) );
463		} || return croak "${@}signature generation failed";
464	}
465}
466
467
468sub _VerifySig {
469	if (DNSSEC) {
470		my $self = shift;
471
472		my $algorithm = $self->algorithm;
473		my $class     = $DNSSEC_verify{$algorithm};
474
475		my $retval = eval {
476			die "algorithm $algorithm not supported\n" unless $class;
477			$class->verify( @_, $self->sigbin );
478		};
479
480		unless ($retval) {
481			$self->{vrfyerrstr} = "${@}signature verification failed";
482			print "\n", $self->{vrfyerrstr}, "\n" if DEBUG;
483			return 0;
484		}
485
486		# uncoverable branch true	# bug in Net::DNS::SEC or dependencies
487		croak "unknown error in $class->verify" unless $retval == 1;
488		print "\nalgorithm $algorithm verification successful\n" if DEBUG;
489		return 1;
490	}
491}
492
493
494sub _ordered() {			## irreflexive 32-bit partial ordering
495	use integer;
496	my ( $n1, $n2 ) = @_;
497
498	return 0 unless defined $n2;				# ( any, undef )
499	return 1 unless defined $n1;				# ( undef, any )
500
501	# unwise to assume 64-bit arithmetic, or that 32-bit integer overflow goes unpunished
502	if ( $n2 < 0 ) {					# fold, leaving $n2 non-negative
503		$n1 = ( $n1 & 0xFFFFFFFF ) ^ 0x80000000;	# -2**31 <= $n1 < 2**32
504		$n2 = ( $n2 & 0x7FFFFFFF );			#  0	 <= $n2 < 2**31
505	}
506
507	return $n1 < $n2 ? ( $n1 > ( $n2 - 0x80000000 ) ) : ( $n2 < ( $n1 - 0x80000000 ) );
508}
509
510
511my $y1998 = timegm( 0, 0, 0, 1, 0, 1998 );
512my $y2026 = timegm( 0, 0, 0, 1, 0, 2026 );
513my $y2082 = $y2026 << 1;
514my $y2054 = $y2082 - $y1998;
515my $m2026 = int( 0x80000000 - $y2026 );
516my $m2054 = int( 0x80000000 - $y2054 );
517my $t2082 = int( $y2082 & 0x7FFFFFFF );
518my $t2100 = 1960058752;
519
520sub _string2time {			## parse time specification string
521	my $arg = shift;
522	return int($arg) if length($arg) < 12;
523	my ( $y, $m, @dhms ) = unpack 'a4 a2 a2 a2 a2 a2', $arg . '00';
524	if ( $arg lt '20380119031408' ) {			# calendar folding
525		return timegm( reverse(@dhms), $m - 1, $y ) if $y < 2026;
526		return timegm( reverse(@dhms), $m - 1, $y - 56 ) + $y2026;
527	} elsif ( $y > 2082 ) {
528		my $z = timegm( reverse(@dhms), $m - 1, $y - 84 );    # expunge 29 Feb 2100
529		return $z < 1456790400 ? $z + $y2054 : $z + $y2054 - 86400;
530	}
531	return ( timegm( reverse(@dhms), $m - 1, $y - 56 ) + $y2054 ) - $y1998;
532}
533
534
535sub _time2string {			## format time specification string
536	my $arg	 = shift;
537	my $ls31 = int( $arg & 0x7FFFFFFF );
538	if ( $arg & 0x80000000 ) {
539
540		if ( $ls31 > $t2082 ) {
541			$ls31 += 86400 unless $ls31 < $t2100;	# expunge 29 Feb 2100
542			my ( $yy, $mm, @dhms ) = reverse( ( gmtime( $ls31 + $m2054 ) )[0 .. 5] );
543			return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1984, $mm + 1, @dhms;
544		}
545
546		my ( $yy, $mm, @dhms ) = reverse( ( gmtime( $ls31 + $m2026 ) )[0 .. 5] );
547		return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1956, $mm + 1, @dhms;
548
549
550	} elsif ( $ls31 > $y2026 ) {
551		my ( $yy, $mm, @dhms ) = reverse( ( gmtime( $ls31 - $y2026 ) )[0 .. 5] );
552		return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1956, $mm + 1, @dhms;
553	}
554
555	my ( $yy, $mm, @dhms ) = reverse( ( gmtime $ls31 )[0 .. 5] );
556	return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1900, $mm + 1, @dhms;
557}
558
559
5601;
561__END__
562
563
564=head1 SYNOPSIS
565
566    use Net::DNS;
567    $rr = Net::DNS::RR->new('name SIG typecovered algorithm labels
568				orgttl sigexpiration siginception
569				keytag signame signature');
570
571    use Net::DNS::SEC;
572    $sigrr = Net::DNS::RR::SIG->create( $string, $keypath,
573					sigval => 10	# minutes
574					);
575
576    $sigrr->verify( $string, $keyrr ) || die $sigrr->vrfyerrstr;
577    $sigrr->verify( $packet, $keyrr ) || die $sigrr->vrfyerrstr;
578
579=head1 DESCRIPTION
580
581Class for DNS digital signature (SIG) resource records.
582
583In addition to the regular methods inherited from Net::DNS::RR the
584class contains a method to sign packets and scalar data strings
585using private keys (create) and a method for verifying signatures.
586
587The SIG RR is an implementation of RFC2931.
588See L<Net::DNS::RR::RRSIG> for an implementation of RFC4034.
589
590=head1 METHODS
591
592The available methods are those inherited from the base class augmented
593by the type-specific methods defined in this package.
594
595Use of undocumented package features or direct access to internal data
596structures is discouraged and could result in program termination or
597other unpredictable behaviour.
598
599
600=head2 algorithm
601
602    $algorithm = $rr->algorithm;
603
604The algorithm number field identifies the cryptographic algorithm
605used to create the signature.
606
607algorithm() may also be invoked as a class method or simple function
608to perform mnemonic and numeric code translation.
609
610=head2 sigexpiration and siginception times
611
612=head2 sigex sigin sigval
613
614    $expiration = $rr->sigexpiration;
615    $expiration = $rr->sigexpiration( $value );
616
617    $inception = $rr->siginception;
618    $inception = $rr->siginception( $value );
619
620The signature expiration and inception fields specify a validity
621time interval for the signature.
622
623The value may be specified by a string with format 'yyyymmddhhmmss'
624or a Perl time() value.
625
626Return values are dual-valued, providing either a string value or
627numerical Perl time() value.
628
629=head2 keytag
630
631    $keytag = $rr->keytag;
632    $rr->keytag( $keytag );
633
634The keytag field contains the key tag value of the KEY RR that
635validates this signature.
636
637=head2 signame
638
639    $signame = $rr->signame;
640    $rr->signame( $signame );
641
642The signer name field value identifies the owner name of the KEY
643RR that a validator is supposed to use to validate this signature.
644
645=head2 signature
646
647=head2 sig
648
649    $sig = $rr->sig;
650    $rr->sig( $sig );
651
652The Signature field contains the cryptographic signature that covers
653the SIG RDATA (excluding the Signature field) and the subject data.
654
655=head2 sigbin
656
657    $sigbin = $rr->sigbin;
658    $rr->sigbin( $sigbin );
659
660Binary representation of the cryptographic signature.
661
662=head2 create
663
664Create a signature over scalar data.
665
666    use Net::DNS::SEC;
667
668    $keypath = '/home/olaf/keys/Kbla.foo.+001+60114.private';
669
670    $sigrr = Net::DNS::RR::SIG->create( $data, $keypath );
671
672    $sigrr = Net::DNS::RR::SIG->create( $data, $keypath,
673					sigval => 10
674					);
675    $sigrr->print;
676
677
678    # Alternatively use Net::DNS::SEC::Private
679
680    $private = Net::DNS::SEC::Private->new($keypath);
681
682    $sigrr= Net::DNS::RR::SIG->create( $data, $private );
683
684
685create() is an alternative constructor for a SIG RR object.
686
687This method returns a SIG with the signature over the data made with
688the private key stored in the key file.
689
690The first argument is a scalar that contains the data to be signed.
691
692The second argument is a string which specifies the path to a file
693containing the private key as generated using dnssec-keygen, a program
694that comes with the ISC BIND distribution.
695
696The optional remaining arguments consist of ( name => value ) pairs
697as follows:
698
699	sigin  => 20191201010101,	# signature inception
700	sigex  => 20191201011101,	# signature expiration
701	sigval => 10,			# validity window (minutes)
702
703The sigin and sigex values may be specified as Perl time values or as
704a string with the format 'yyyymmddhhmmss'. The default for sigin is
705the time of signing.
706
707The sigval argument specifies the signature validity window in minutes
708( sigex = sigin + sigval ).
709
710By default the signature is valid for 10 minutes.
711
712=over 4
713
714=item *
715
716Do not change the name of the private key file.
717The create method uses the filename as generated by dnssec-keygen
718to determine the keyowner, algorithm, and the keyid (keytag).
719
720=back
721
722=head2 verify
723
724    $verify = $sigrr->verify( $data, $keyrr );
725    $verify = $sigrr->verify( $data, [$keyrr, $keyrr2, $keyrr3] );
726
727The verify() method performs SIG0 verification of the specified data
728against the signature contained in the $sigrr object itself using
729the public key in $keyrr.
730
731If a reference to a Net::DNS::Packet is supplied, the method performs
732a SIG0 verification on the packet data.
733
734The second argument can either be a Net::DNS::RR::KEYRR object or a
735reference to an array of such objects. Verification will return
736successful as soon as one of the keys in the array leads to positive
737validation.
738
739Returns false on error and sets $sig->vrfyerrstr
740
741=head2 vrfyerrstr
742
743    $sig0 = $packet->sigrr || die 'not signed';
744    print $sig0->vrfyerrstr unless $sig0->verify( $packet, $keyrr );
745
746    $sigrr->verify( $packet, $keyrr ) || die $sigrr->vrfyerrstr;
747
748=head1 REMARKS
749
750The code is not optimised for speed.
751
752If this code is still around in 2100 (not a leap year) you will
753need to check for proper handling of times after 28th February.
754
755=head1 ACKNOWLEDGMENTS
756
757Although their original code may have disappeared following redesign of
758Net::DNS, Net::DNS::SEC and the OpenSSL API, the following individual
759contributors deserve to be recognised for their significant influence
760on the development of the SIG package.
761
762Andy Vaskys (Network Associates Laboratories) supplied code for RSA.
763
764T.J. Mather provided support for the DSA algorithm.
765
766
767=head1 COPYRIGHT
768
769Copyright (c)2001-2005 RIPE NCC,   Olaf M. Kolkman
770
771Copyright (c)2007-2008 NLnet Labs, Olaf M. Kolkman
772
773Portions Copyright (c)2014 Dick Franks
774
775All rights reserved.
776
777Package template (c)2009,2012 O.M.Kolkman and R.W.Franks.
778
779
780=head1 LICENSE
781
782Permission to use, copy, modify, and distribute this software and its
783documentation for any purpose and without fee is hereby granted, provided
784that the above copyright notice appear in all copies and that both that
785copyright notice and this permission notice appear in supporting
786documentation, and that the name of the author not be used in advertising
787or publicity pertaining to distribution of the software without specific
788prior written permission.
789
790THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
791IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
792FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
793THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
794LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
795FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
796DEALINGS IN THE SOFTWARE.
797
798
799=head1 SEE ALSO
800
801L<perl>, L<Net::DNS>, L<Net::DNS::RR>, L<Net::DNS::SEC>,
802RFC4034, RFC3755, RFC3008, RFC2931, RFC2535
803
804L<Algorithm Numbers|http://www.iana.org/assignments/dns-sec-alg-numbers>
805
806L<BIND 9 Administrator Reference Manual|http://www.bind9.net/manuals>
807
808=cut
809