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