Net-DNS-SEC-0.21/0000755000175100017510000000000012422405450012560 5ustar willemwillemNet-DNS-SEC-0.21/t/0000755000175100017510000000000012422405450013023 5ustar willemwillemNet-DNS-SEC-0.21/t/12-nsec++.t0000644000175100017510000000660012422405404014507 0ustar willemwillem#!/usr/bin/perl -sw # Test script for dnssec functionalty # $Id: 12-nsec++.t 1112 2013-09-20 08:57:49Z willem $ # use Net::DNS::SEC; use Test::More tests=>17; use Data::Dumper; use Net::DNS::RR::NSEC3 qw( name2hash ); use strict; BEGIN {use_ok('Net::DNS'); } # test 1 # Example draft-ietf-dnsext-nsec-rdata-01 my $typebmhex=" 00 06 40 01 00 00 00 03 04 1b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20"; $typebmhex=~ s/\s//g; my $typebm=pack("H*",$typebmhex); is (join(" ",Net::DNS::RR::NSEC::_typebm2typearray($typebm)),"A MX NSEC RRSIG TYPE1234","typebmhex function returns expected"); my @typearray=qw(A MX RRSIG NSEC TYPE1234); $typebm=Net::DNS::RR::NSEC::_typearray2typebm(@typearray); ok(my $rr=Net::DNS::RR->new("alfa.example.com 86400 IN NSEC host.example.com A MX TYPE1234 NSEC RRSIG "), "NSEC generated"); is( $rr->typelist,"A MX NSEC RRSIG TYPE1234","Typelist Correctly generated"); is ($rr->nxtdname,"host.example.com", "nxtdname correctly parsed"); is (unpack("H*",$rr->typebm),$typebmhex,"Typebitmap generated correctly"); # Testing the construction of a new object using hashes and using typelist # instead of bitmaps. my $rr2=Net::DNS::RR->new(name=> "alfa.example.com", ttl=> 86400, type=>"NSEC", nxtdname=>"host.example.com", typelist=>" A MX TYPE1234 NSEC RRSIG ", ); is( unpack("H*",$rr2->typebm()), unpack("H*",$rr->typebm()), "typebitmaps equal"); is( join(" ", sort split(' ',$rr2->typelist())), join(" ", sort split(' ',$rr->typelist())), "typelists equal"); my $newbitmap="00060008000000031606000000000002"; my $newtypelist="NSEC PTR RRSIG TYPE5678"; $rr->typelist($newtypelist); is (unpack("H*",$rr->typebm()),$newbitmap,"typebm changed appropriately after invoking typelist method"); $rr2->typebm(pack("H*",$newbitmap)); is ($rr2->typelist,$newtypelist,"typelist changed appropriately after invoking typelist method"); ######################## my $foo={};; bless($foo,"Net::DNS::RR::NSEC3"); $foo->salt("aabbccdd"); # H(example) = 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom is ("0p9mhaveqvm6t7vbl5lop2u3t2rp3tom",lc Net::DNS::RR::NSEC3::name2hash(1,"example.",12,$foo->saltbin),"name2hash over example"); # H(x.w.example) = b4um86eghhds6nea196smvmlo4ors995 is ("b4um86eghhds6nea196smvmlo4ors995",lc Net::DNS::RR::NSEC3::name2hash(1,"x.w.example.",12,$foo->saltbin),"name2hash over example"); # H(c.x.w.example) = 0va5bpr2ou0vk0lbqeeljri88laipsfh is ("0va5bpr2ou0vk0lbqeeljri88laipsfh",lc Net::DNS::RR::NSEC3::name2hash(1,"c.x.w.example.",12,$foo->saltbin),"name2hash over example"); # H(*.x.w.example) = 92pqneegtaue7pjatc3l3qnk738c6v5m is ("92pqneegtaue7pjatc3l3qnk738c6v5m",lc Net::DNS::RR::NSEC3::name2hash(1,"*.x.w.example.",12,$foo->saltbin),"name2hash over example"); my $nsec3param = eval{ Net::DNS::RR->new("alfa.example.com 86400 NSEC3PARAM 2 0 12 aabbccdd") }; print $@ if $@; ok ($nsec3param, "NSEC3PARAM created"); $nsec3param = eval{ Net::DNS::RR->new("alfa.example.com 86400 NSEC3PARAM 2 0 12 aabbccfs") }; print $@ if $@; ok (!$nsec3param, "NSEC3PARAM not created with corrupt hex data"); my $hashalg=Net::DNS::SEC->digtype("SHA1"); my $salt=pack("H*","aabbccdd"); my $iterations=12; my $name="*.x.w.example"; my $hashedname= name2hash($hashalg,$name,$iterations,$salt); is( $hashedname,"92pqneegtaue7pjatc3l3qnk738c6v5m","name2hash exports and works"); Net-DNS-SEC-0.21/t/10-keyset.t0000644000175100017510000003103712422405404014735 0ustar willemwillem#!/usr/bin/perl -sw # Test script for keyset functionality # $Id: 10-keyset.t 1209 2014-05-29 10:19:07Z willem $ # # Called in a fashion similar to: # /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-freebsd \ # -I/usr/lib/perl5/5.6.1 -e 'use Test::Harness qw(&runtests $verbose); \ # $verbose=0; runtests @ARGV;' t/10-keyset.t use strict; BEGIN { use Test::More tests => 21; use_ok('Net::DNS::SEC'); # test 1 use_ok('Net::DNS::Keyset'); # test 2 } # # RSA keypair # my $keypathrsa = "Ktest.tld.+005+15791.private"; my $privrsakey = << 'ENDRSA'; Private-key-format: v1.2 Algorithm: 5 (RSASHA1) Modulus: tYGOVBZbUOH9GR51zxUGX3EEDaVyua9EZNOayy5mNF3gNZbvHpO1tVR7AY5IHvVlO3n3ad1OGpsVC0TEI+xdAcjit9fGoGqdrCFmDdd41dUS8ReRj8i6vradooRMiPMdD/HPUc4FZ9YseF3KKvryplqg09YxxOKAWPw8yPIMric= PublicExponent: Aw== PrivateExponent: eQEJjWQ84Jaou2mj32NZlPYCs8Oh0R+C7eJnMh7uzZPqzmSfabfOeOL8q7QwFKOY0lFPm+jevGdjXNiCwp2TVWZrFINEMwUpxPJCvQQLh0k9Ah3NN2ELPBSlUjkRa10KaRSVSdDaYUM9X1/ZT/9RQagi4ckuy0x6UcRmoSng/Ms= Prime1: 3SNqKvY2geGDxgpqUKy2gGKq2LBRZ0CruBsVQXtoBH2dwq1bUScC9HxrTYaGxn2BELZsYRMeGVqZ1WqzsLXeTw== Prime2: 0h6u5+odYP2A7/eIALrUZtTDEi1rT+k434qR7Tb/4w/UkEIHw5bS/NP+AH2sNXtCzbYUx1h11m5EgDgjgoVUqQ== Exponent1: k2zxcfl5q+utLrGcNch5quxx5crg74Byery41lJFWFO+gcjni29XTahHiQRZ2akAtc7y62IUEOcROPHNIHk+3w== Exponent2: jBR0mpwTlf5V9U+wAHyNmeMstsjyNUYl6lxhSM9VQgqNtYFagmSMqI1UAFPII6eB3nljL5BOjvQtqtAXrFjjGw== Coefficient: YJYWzNpbdj/11mE4kUwaiH9GQbY+uA28tv4aVAwAEcKPaU1QQ2k8Jlm+VXxh9v02QCFJYln3416972oeCx9eyw== ENDRSA open( RSA, ">$keypathrsa" ) or die "Could not open $keypathrsa"; print RSA $privrsakey; close(RSA); my $rsakeyrr = new Net::DNS::RR( "test.tld. IN DNSKEY 256 3 5 AQO1gY5UFltQ4f0ZHnXPFQZfcQQNpXK5r0Rk05rLLmY0XeA1lu8ek7W1 VHsBjkge9WU7efdp3U4amxULRMQj7F0ByOK318agap2sIWYN13jV1RLx F5GPyLq+tp2ihEyI8x0P8c9RzgVn1ix4Xcoq+vKmWqDT1jHE4oBY/DzI 8gyuJw==" ); ok( $rsakeyrr, 'RSA public key created' ); # test 3 my $keypathdsa = "Ktest.tld.+003+09734.private"; my $privdsakey = << 'ENDDSA'; Private-key-format: v1.2 Algorithm: 3 (DSA) Prime(p): 7m5wm/8KMO1fLaBB2Wbq3s0/jMudrauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/joY2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srlslykC+LQRnsbxB5YJMgmkPaPZU8GpRcc= Subprime(q): jRgd5fwOUwUmNpcD6Uzs/tMzy3U= Base(g): a0/+JhZhnci+P8/GOvnokG3NAF10o0Pf6/oz5UpcmX89KqjPvn9aRTRI9sM2AJgFBkzrQhXcx9NPvhneW0zN/baQhaUkupJ8YazNkkVKfOM6aH9h8ONVgGNRiLEBILQa07EMzce9/+JDYFbOCajJqhb9MZlTau17GDDK+r4okJ0= Private_value(x): C7O98kp8pfDdqeuvD83nf1xc4sI= Public_value(y): kFKU1HfmfRxPWwS9mA3FBHZ9LbmEizsH7vFSD7m31crIDVpxIO02bhKyFAuurKNh6naG4iTo3ak0yv6/bP8VNFIxN2QHPnnQL72ctUpvMLe+kWX7fGXuXWPIUCWVnbAeP2SnxpjxU039E9A2Rk6Dp9Eu0oXsM8hcUUnRv6ekycA= ENDDSA open( DSA, ">$keypathdsa" ) or die "Could not open $keypathdsa"; print DSA $privdsakey; close(DSA); my $dsakeyrr = new Net::DNS::RR( "test.tld. IN DNSKEY 256 3 3 CI0YHeX8DlMFJjaXA+lM7P7TM8t17m5wm/8KMO1fLaBB2Wbq3s0/jMud rauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/jo Y2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srls lykC+LQRnsbxB5YJMgmkPaPZU8GpRcdrT/4mFmGdyL4/z8Y6+eiQbc0A XXSjQ9/r+jPlSlyZfz0qqM++f1pFNEj2wzYAmAUGTOtCFdzH00++Gd5b TM39tpCFpSS6knxhrM2SRUp84zpof2Hw41WAY1GIsQEgtBrTsQzNx73/ 4kNgVs4JqMmqFv0xmVNq7XsYMMr6viiQnZBSlNR35n0cT1sEvZgNxQR2 fS25hIs7B+7xUg+5t9XKyA1acSDtNm4SshQLrqyjYep2huIk6N2pNMr+ v2z/FTRSMTdkBz550C+9nLVKbzC3vpFl+3xl7l1jyFAllZ2wHj9kp8aY 8VNN/RPQNkZOg6fRLtKF7DPIXFFJ0b+npMnA" ); ok( $dsakeyrr, 'RSA public key created' ); # test 4 # Create keysets my $datarrset = [$rsakeyrr, $dsakeyrr]; my $sigrsa = create Net::DNS::RR::RRSIG( $datarrset, $keypathrsa, ( ttl => 360, #sigval => 100, ) ); my $sigdsa = create Net::DNS::RR::RRSIG( $datarrset, $keypathdsa, ( ttl => 360, #sigval => 100, ) ); ok( $sigrsa, 'RSA signature created' ); # test 5 my $keysetpath = "t/keyset-test.tld."; open( KEYSET, ">$keysetpath" ) or die "Could not open $keysetpath"; print KEYSET $rsakeyrr->string, "\n"; print KEYSET $dsakeyrr->string, "\n"; print KEYSET $sigrsa->string, "\n"; print KEYSET $sigdsa->string, "\n"; close(KEYSET); my $keyset; $keyset = Net::DNS::Keyset->new($keysetpath); is( ref($keyset), "Net::DNS::Keyset", "Keyset object read" ); # test 6 undef $keyset; $keyset = Net::DNS::Keyset->new($datarrset); is( ref($keyset), "Net::DNS::Keyset", "Keyset object created" ); # test 7 my @ds = $keyset->extract_ds; my $string0 = join ' ', split /\s+/, lc $ds[0]->string; my $string1 = join ' ', split /\s+/, lc $ds[1]->string; if ( eval { require Digest::BubbleBabble; } ) { is( $string0, lc( "test.tld. 0 IN DS 15791 5 1 C355F0F3F30C69BF2F7EA253ED82FBC280C2496B ; xuboh-hasiz-fosab-super-zyrol-vimuh-firom-dyvos-debis-daduk-rexix" ), "DS 1 generated from keyset" ); # test 8-with babble is( $string1, lc( "test.tld. 0 IN DS 9734 3 1 0e045bfe67dec6e54d0f1338877a53841902ab4a ; xefib-gakiz-vynat-vacov-hyfeb-zugif-mecil-pegam-gykib-dapyg-pexox" ), "DS 1 generated from keyset" ); # test 9-with babble } else { is( $string0, lc("test.tld. 0 IN DS 15791 5 1 C355F0F3F30C69BF2F7EA253ED82FBC280C2496B"), "DS 1 generated from keyset" ); # test 8-without babble is( $string1, lc("test.tld. 0 IN DS 9734 3 1 0e045bfe67dec6e54d0f1338877a53841902ab4a"), "DS 1 generated from keyset" ); # test 9-without babble } ## # Corrupted keyset $keysetpath = "keyset-test-corrupt.tld."; open( KEYSET, ">$keysetpath" ) or die "Could not open $keysetpath"; print KEYSET $rsakeyrr->string, "\n"; print KEYSET $dsakeyrr->string, "\n"; my $sigstr = $sigrsa->string; $sigstr =~ tr/A-Z/a-z/; # corrupt the base64 signature $sigstr =~ s/in rrsig dnskey/IN RRSIG DNSKEY/; # fix what should not have been corrupted print KEYSET $sigstr . "\n"; print KEYSET $sigdsa->string . "\n"; close(KEYSET); $keyset = Net::DNS::Keyset->new($keysetpath); ok( !$keyset, "Corrupted keyset not loaded" ); # test 10 is( $Net::DNS::Keyset::keyset_err, "RSA Verification failed on key test.tld 15791 ", "Correct Error message" ) ; # test 11 # # The packet contains a keyset as returned from a bind nameserver # the keyset is signed with a signature valid until 2030 06 .. # After that the test may fail :-) # This is the code snippet used to get such a little packet as below. #use Net::DNS::Resolver; #my $res=Net::DNS::Resolver->new(); #$res->nameserver("10.0.53.204"); #$res->dnssec(1); #my $a_packet=$res->send("sub.tld","DNSKEY"); #$a_packet->print; #print unpack("H*",$a_packet->data); my $UUencodedPacket = "e6cc81a000010004000000010373756203746c 640000300001c00c00300001000000200086010103050103bc54beaee1 1dc1a29ba945bf69d0db27b364b2dfe60396efff4c6fb359127ea696e1 4c66e1c6d23cd6f6c335e1679c61dd3fa4d68a689b8709ea686e43f175 6831193903613f6a5f3ff039b21eed9faad4edcb43191c76490ca0947a 9fa726740bc4449d6c58472a605913337d2dbddc94a7271d25c358fdaa 60fe1272a5f8b9c00c00300001000000200086010003050103f6d63a8a b9f775a0c7194d67edb5f249bf398c3d27d2985facf6fb7e25cc35c876 2eb8ea22200c847963442fb6634916dc2ec21cdbf2c7378799b8e7e399 e751ca1e25133349cab52ebf3fe8a5bc0239c28d64f4d8f609c191a7d2 d364578a159701ef73af93946b281f0aac42b42be17362c68d7a54bbb8 fa7bc6f70f455a75c00c002e000100000020009b003005020000006470 dc814040c02ced39d40373756203746c6400a7d9db75a4115794f871ec 71fc7469c74a6be1cf95434a00363506b354bf15656f7556c51355c8dc ac7f6c0a4061c0923e0bf341094e586619c2cb316949772ce5bd1e9949 f91b016f7e6bee0f6878e16b6e59ece086f8d5df68f048524e1bff3c09 dd15c203d28416600e936451d1646e71611ec95e12d709839369cbc442 c0c00c002e000100000020009b003005020000006470dc814040c02ced fbaf0373756203746c640017c6e59f317119da812c6b1e175e8aaec742 35a4bfad777e7759fa2daf7959f9611c26e11adde9bdc901c624ca6965 7b79653495e22647c5e0e5bedfe5524397d769d816746d10b2067472b4 f9b04fbde8e39d7861bd6773c80f632f55b46c7a537a83f0b5a50200c9 d2847b71d9dfaa643f558383e6e13d4e75f70029849444000029100000 0080000000"; $UUencodedPacket =~ s/\n//g; $UUencodedPacket =~ s/\s//g; my $packetdata = pack( "H*", $UUencodedPacket ); my $packet = Net::DNS::Packet->new( \$packetdata ); $keyset = Net::DNS::Keyset->new($packet); is( ref($keyset), "Net::DNS::Keyset", "Keyset object from packet" ); # test 12 is( join( " ", sort( $keyset->verify ) ), "14804 64431", "Verify method returned the two proper keytags" ); # test 13 my $keyset2 = Net::DNS::Keyset->new( $datarrset, "./" ); is( ref($keyset2), "Net::DNS::Keyset", "Keyset object from DNSKEY RR and signature" ); # test 14 #print $Net::DNS::Keyset::keyset_err; #$keyset->print; unlink($keysetpath); ######### ### my $rr; my @keyrr; my @keyrr2; my @sigrr; # Note that the order of pushing the RRs is important for successful testing. # All signatures have expiration date in 2030... this test should work for a while $rr = Net::DNS::RR->new( "example.com 100 IN DNSKEY 256 3 5 ( AQOxFlzX8vShSG3JG2J/fngkgy64RoWr8ovG e7MuvPJqOMHTLM5V8+TJIahSoyUd990ictNv hDegUqLtZ8k5oQq44viFCU/H1apdEaJnLnXs cVo+08ATlEb90MYznK9K0pm2ixbyspzRrrXp nPi9vo9iU2xqWqw/Efha4vfi6QVs4w== ) " ); push( @keyrr, $rr ); push( @keyrr2, $rr ); $rr = Net::DNS::RR->new( "example.com 100 IN DNSKEY 256 3 5 ( AQO4jhl6ilWV2mYjwWl7kcxrYyQsnnbV7pxX m48p+SgAr+R5SKyihkjg86IjZBQHFJKZ8RsZ dhclH2dikM+53uUEhrqVGhsqF8FsNi4nE9aM ISiX9Zs61pTYGYboYDvgpD1WwFbD4YVVlfk7 rCDP/zOE7H/AhkOenK2w7oiO0Jehcw== ) " ); push( @keyrr, $rr ); push( @keyrr2, $rr ); my $poppedkey = Net::DNS::RR->new( $rr->string ); $rr = Net::DNS::RR->new( "example.com 100 IN DNSKEY 256 3 5 ( AQO5fWabr7bNxDXT8YrIeclI9nvYYdKni3ef gJfU749O3QVX9MON6WK0ed00odQF4cLeN3vP SdhasLDI3Z3TzyAPBQS926oodxe78K9zwtPT 1kzJxvunOdJr6+6a7/+B6rF/cwfWTW50I0+q FykldldB44a1uS34u3HgZRQXDmAesw== ) " ); push( @keyrr, $rr ); push( @keyrr2, $rr ); $rr = Net::DNS::RR->new( "example.com 100 IN DNSKEY 256 3 5 ( AQO6uGWsox2oH36zusGA0+w3uxkZMdByanSC jiaRHtkOA+gIxT8jmFvohxQBpVfYD+xG2pt+ qUWauWPFPjsIUBoFqHNpqr2/B4CTiZm/rSay HDghZBIMceMa6t4NpaOep79QmiE6oGq6yWRB swBkPZx9uZE7BqG+WLKEp136iwWyyQ== ) " ); push( @keyrr, $rr ); push( @keyrr2, $rr ); $rr = Net::DNS::RR->new( "example.com 100 IN RRSIG DNSKEY 5 2 100 20300101000000 ( 20040601105519 11354 example.com. GTqyJTRbKJ0LuWbAnNni1M4JZ1pn+nXY1Zuz Z0Kvt6OMTYCAFMFt0Wv9bncYkUuUSMGM7yGG 9Z7g7tcdb4TKCqQPYo4gr3Qj/xgC4LESoQs0 yAsJtLUiDfO6e4aWHmanpMGyGixYzHriS1pt SRzirL1fTgV+kdNs5zBatUHRnQc=) " ); push( @sigrr, $rr ); $rr = Net::DNS::RR->new( "example.com 100 IN RRSIG DNSKEY 5 2 100 20300101000000 ( 20040601105519 28109 example.com. WemQqA+uaeKqCy6sEVBU3LDORG3f+Zmix6qK 9j1WL83UMWdd6sxNh0QJ0YL54lh9NBx+Viz7 gajO+IM4MmayxKY4QVjp+6mHeE5zBVHMpTTu r5T0reNtTsa8sHr15fsI49yn5KOvuq+DKG1C gI6siM5RdFpDsS3Rmf8fiK1PyTs= )" ); push( @sigrr, $rr ); $rr = Net::DNS::RR->new( "example.com 100 IN RRSIG DNSKEY 5 2 100 20300101000000 ( 20040601105519 33695 example.com. M3yVwTOMw+jAKYY5c6oS4DH7OjOdfMOevpIe zdKqWXkehoDg9YOwz8ai17AmfgkjZnsoNu0W NMIcaVubR3n02bkVhJb7dEd8bhbegF8T1xkL 7rf9EQrPmM5GhHmVC90BGrcEhe//94hdXSVU CRBi6KPFWSZDldd1go133bk/b/o= )" ); push( @sigrr, $rr ); $rr = Net::DNS::RR->new( "example.com 100 IN RRSIG DNSKEY 5 2 100 20300101000000 ( 20040601105519 39800 example.com. Mmhn2Ql6ExmyHvZFWgt+CBRw5No8yM0rdH1b eU4is5gRbd3I0j5z6PdtpYjAkWiZNdYsRT0o P7TQIsADfB0FLIFojoREg8kp+OmbpRTsLTgO QYC95u5WodYGz03O0EbnQ7k4gkje6385G40D JVl0xVfujHBMbB+keiSphD3mG4I= )" ); push( @sigrr, $rr ); my @errors; my $ks = Net::DNS::Keyset->new( \@keyrr, \@sigrr ); ok( $ks, "Keyset created from two arrays." ); my @result; @result = $ks->keys; ok( eq_array( \@result, \@keyrr ), "Keys out equal to keys in" ); # test 16 @result = $ks->sigs; ok( eq_array( \@result, \@sigrr ), "Sigs out equal to sigs in" ); # test 17 $datarrset = [$rsakeyrr, $dsakeyrr]; $sigrsa = create Net::DNS::RR::RRSIG( $datarrset, $keypathrsa, ( ttl => 360, #sigval => 100, ) ); $sigdsa = create Net::DNS::RR::RRSIG( $datarrset, $keypathdsa, ( ttl => 360, #sigval => 100, ) ); ok( $sigrsa, 'RSA signature created' ); # test 18 open( KEYSET, ">$keysetpath" ) or die "Could not open $keysetpath"; print KEYSET $rsakeyrr->string . "\n"; print KEYSET $dsakeyrr->string . "\n"; print KEYSET $sigrsa->string . "\n"; close(KEYSET); $keyset = Net::DNS::Keyset->new($keysetpath); is( join( " ", sort( $keyset->verify ) ), "15791", "Verify method returned the keytags" ); # test 19 ok( !$keyset->verify(9734), "Verification against keytag 9734 failed" ); # test 20 is( $Net::DNS::Keyset::keyset_err, "No signature made with 9734 found", "Correct Error message" ); # test 21 unlink($keysetpath); unlink($keypathdsa); unlink($keypathrsa); exit; Net-DNS-SEC-0.21/t/11-sigstress.t0000644000175100017510000001653712422405404015470 0ustar willemwillem#!/usr/bin/perl -sw # Test script for dnssec functionalty # $Id: 11-sigstress.t 1171 2014-02-26 08:56:52Z willem $ # # Called in a fashion simmilar to: # /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-freebsd \ # -I/usr/lib/perl5/5.6.1 -e 'use Test::Harness qw(&runtests $verbose); \ # $verbose=0; runtests @ARGV;' t/09-dnssec.t use constant LOOPS=>50; use Test::More tests=> (LOOPS * 9 + 3 ); # 3 tests befor the loop, 9 inside. use strict; use Net::DNS::SEC; ######## #### Couple of SIG0 and RRSIG tests diag("This may take a while, do not worry."); # # RSA keypair # my $keypathrsa="t/Ktest.tld.+001+42495.private"; my $privrsakey= << 'ENDRSA' ; Private-key-format: v1.2 Algorithm: 1 (RSA) Modulus: ovtC5gQH1fuAnQqMvNctGfX3o2F82164fO7toGiWddiLTuWxrXoHwcpIFLO+hJR9Xxr1gaWh6od66CJnOzBpIQjIe/htpRO2nmLFF5+cB3QRRMGQWmq3bPCXDBHE/Jx8ihzWZavXwIUN+oLqhnWbkT6sYGH8M+9VSW9rfeil/+c= PublicExponent: Aw== PrivateExponent: bKeB7q1ajqerE1xd0zoeEU6lF5ZTPOnQU0nzwEW5o+WyNJkhHlFagTGFYyJ/Aw2o6hH5ARkWnFpR8BbvfMrwv6AeCrahtJgilCpCYxwusOOikbkGR/sXP5ObscRmEuhfzVYBV62yMc34MyspHzXHNZAL+SgRswopy6MgWdAII2s= Prime1: 0GNRLAYLvgaIZ+8o/fVST6WEhQd4bDIEHnBtIxHj9NIrHL/nIerA80sth+Pwfed2zp109U+zvcizUSfJDbHRsQ== Prime2: yDgaunUKcXw3u3JZ92Crzvflpv92BeKJdL0USBn8Sxqq/xR7BWG03M6AOkjnJwlKF/z1sJHzok3kqZMuIuf5Fw== Exponent1: iuzgyAQH1ARa7/TF/qOMNRkDA1pQSCFYFErzbLaX+IwcvdVEwUcrTNzJBUKgU++kib5N+N/NKTB3i2/bXnaLyw== Exponent2: hXq8fE4G9lLP0kw7+kByifqZGf+kA+xboyi4MBFS3Lxx/2L8rkEjPd8AJttExLDcD/35IGFNFt6YcQzJbJqmDw== Coefficient: gAeUUI6YOtdNAh3kS7pOzYfn0ZrUCV8bGpZoaXANk2RL2zUiaSSa4wudhpHwMJt+psNkkiQyf4v600uHbxro4Q== ENDRSA my $rsakeyrr=new Net::DNS::RR ("test.tld. IN DNSKEY 256 3 1 AQOi+0LmBAfV+4CdCoy81y0Z9fejYXzbXrh87u2gaJZ12ItO5bGtegfB ykgUs76ElH1fGvWBpaHqh3roImc7MGkhCMh7+G2lE7aeYsUXn5wHdBFE wZBaards8JcMEcT8nHyKHNZlq9fAhQ36guqGdZuRPqxgYfwz71VJb2t9 6KX/5w=="); ok( $rsakeyrr, 'RSA public key created'); # test 1 open (RSA,">$keypathrsa") or die "Could not open $keypathrsa"; print RSA $privrsakey; close(RSA); my $keypathrsasha1="t/Ktest.tld.+005+32972.private"; my $privrsasha1key= << 'ENDRSASHA1' ; Private-key-format: v1.2 Algorithm: 5 (RSASHA1) Modulus: mI5MpW3OGQbD3X9aW9xCYbeKeyXh+NTOL1vts93rKuyq/cLIZsrJVG5LZlWHa7kEL3I1c0qj3fPZww6HRWtJeDZlSC3U81XeTE4z1vlJHYITiiLcyqUX1qK3/CGKeU6OlvhDL6mglshW2pPvKEs/SWEIRLP0/gahH0fJ1SAVfq8= PublicExponent: Aw== PrivateExponent: ZbQzGPPeu1nX6P+RkpLW68+xp26WpeM0H5Ked+lHcfMcqSyFmdyGOEmHmY5aR9CtdPbOTNxtPqKRLLRaLkeGTxyyxxapT8seZu5+r+Xniq+F+iHFG9nvQW+gB03WRvLJUf//mDKt7qBnXRVTqh51BXMQR5S80afmFMEFf8Q3hMs= Prime1: yjowRynvf+0mtTXljuFkKvq0xYNlts5ArRhSNV4+HRcSHCjrMGwbkJKQIhU38JxaVUPsBp8WA+geGxZCxBUXNw== Prime2: wR7tRK0MJUOLMz/pkYxpT8/eKrG7J2Kzzi+e92rQxUmJ3BrgLS+VRyk+0dxxLPNm3yvtTjqtht/iCytSta0gSQ== Exponent1: htF1hMafqp4ZziPuX0Dtcfx4g6zued7VyLrheOl+vg9haBtHdZ1ntbcKwWN6oGg8ONfyrxS5V/AUEg7XLWNkzw== Exponent2: gL9I2HNdbi0Hd3/xC7Lw39/pccvSGkHNNB+/T5yLLjEGkryVc3UOL3DUi+hLc0zvP3KeNCceWeqWshzhznNq2w== Coefficient: XST5nq13vpLpNiATuLDRWc5HvJfrZ6qw2qYgKBJ635Fye4N8XUM9Gxm1DxVrhJnSjER4r7WgqMmcnJyP39VCAw== ENDRSASHA1 my $rsasha1keyrr=new Net::DNS::RR ("test.tld. IN DNSKEY 256 3 5 AQOYjkylbc4ZBsPdf1pb3EJht4p7JeH41M4vW+2z3esq7Kr9wshmyslU bktmVYdruQQvcjVzSqPd89nDDodFa0l4NmVILdTzVd5MTjPW+UkdghOK ItzKpRfWorf8IYp5To6W+EMvqaCWyFbak+8oSz9JYQhEs/T+BqEfR8nV IBV+rw=="); ok( $rsasha1keyrr, 'RSASHA1 public key created'); # test 2 open (RSASHA1,">$keypathrsasha1") or die "Could not open $keypathrsasha1"; print RSASHA1 $privrsasha1key; close(RSASHA1); my $keypathdsa="t/Ktest.tld.+003+09734.private"; my $privdsakey= << 'ENDDSA' ; Private-key-format: v1.2 Algorithm: 3 (DSA) Prime(p): 7m5wm/8KMO1fLaBB2Wbq3s0/jMudrauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/joY2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srlslykC+LQRnsbxB5YJMgmkPaPZU8GpRcc= Subprime(q): jRgd5fwOUwUmNpcD6Uzs/tMzy3U= Base(g): a0/+JhZhnci+P8/GOvnokG3NAF10o0Pf6/oz5UpcmX89KqjPvn9aRTRI9sM2AJgFBkzrQhXcx9NPvhneW0zN/baQhaUkupJ8YazNkkVKfOM6aH9h8ONVgGNRiLEBILQa07EMzce9/+JDYFbOCajJqhb9MZlTau17GDDK+r4okJ0= Private_value(x): C7O98kp8pfDdqeuvD83nf1xc4sI= Public_value(y): kFKU1HfmfRxPWwS9mA3FBHZ9LbmEizsH7vFSD7m31crIDVpxIO02bhKyFAuurKNh6naG4iTo3ak0yv6/bP8VNFIxN2QHPnnQL72ctUpvMLe+kWX7fGXuXWPIUCWVnbAeP2SnxpjxU039E9A2Rk6Dp9Eu0oXsM8hcUUnRv6ekycA= ENDDSA my $dsakeyrr=new Net::DNS::RR ("test.tld. IN DNSKEY 256 3 3 CI0YHeX8DlMFJjaXA+lM7P7TM8t17m5wm/8KMO1fLaBB2Wbq3s0/jMud rauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/jo Y2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srls lykC+LQRnsbxB5YJMgmkPaPZU8GpRcdrT/4mFmGdyL4/z8Y6+eiQbc0A XXSjQ9/r+jPlSlyZfz0qqM++f1pFNEj2wzYAmAUGTOtCFdzH00++Gd5b TM39tpCFpSS6knxhrM2SRUp84zpof2Hw41WAY1GIsQEgtBrTsQzNx73/ 4kNgVs4JqMmqFv0xmVNq7XsYMMr6viiQnZBSlNR35n0cT1sEvZgNxQR2 fS25hIs7B+7xUg+5t9XKyA1acSDtNm4SshQLrqyjYep2huIk6N2pNMr+ v2z/FTRSMTdkBz550C+9nLVKbzC3vpFl+3xl7l1jyFAllZ2wHj9kp8aY 8VNN/RPQNkZOg6fRLtKF7DPIXFFJ0b+npMnA"); ok( $dsakeyrr, 'RSA public key created'); # test 3 open (DSA,">$keypathdsa") or die "Could not open $keypathdsa"; print DSA $privdsakey; close(DSA); my $datarrset=[$dsakeyrr, $rsakeyrr, $rsasha1keyrr]; my $PrivateRSA=Net::DNS::SEC::Private->new($keypathrsa); my $PrivateRSASHA1=Net::DNS::SEC::Private->new($keypathrsasha1); my $PrivateDSA=Net::DNS::SEC::Private->new($keypathdsa); for (my $i=0;$inew("test.test"); $update_rsa->push("update", Net::DNS::rr_add("test.test.test 3600 IN A 10.0.0.1")); $update_rsa->sign_sig0($PrivateRSA); my $update_rsasha1 = Net::DNS::Update->new("test.test"); $update_rsasha1->push("update", Net::DNS::rr_add("test.test.test 3600 IN A 10.0.0.1")); $update_rsasha1->sign_sig0($PrivateRSASHA1); my $update_dsa = Net::DNS::Update->new("test.test"); $update_dsa->push("update", Net::DNS::rr_add("test.test.test 3600 IN A 10.0.0.1")); $update_dsa->sign_sig0($PrivateDSA); $update_rsa->data; $update_rsasha1->data; $update_dsa->data; my $sigrrsa=$update_rsa->pop("additional"); my $sigrrsasha1=$update_rsasha1->pop("additional"); my $sigrrdsa=$update_dsa->pop("additional"); ok ($sigrrsa->verify($update_rsa, $rsakeyrr),'RSA SIG0 verification of packet data'); is( $sigrrsa->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); ok ($sigrrsasha1->verify($update_rsasha1, $rsasha1keyrr),'RSASHA1 SIG0 verification of packet data'); is( $sigrrsasha1->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); ok ($sigrrdsa->verify($update_dsa, $dsakeyrr),'DSA SIG0 verification of packet data'); is( $sigrrdsa->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); my $sigdsa= create Net::DNS::RR::RRSIG($datarrset,$keypathdsa, ( ttl => 360, # sigval => 100, )); # Verify the just created signatures ok ($sigdsa->verify($datarrset,$dsakeyrr), 'DSA sig verifies'); my $sigrsa= create Net::DNS::RR::RRSIG($datarrset,$keypathrsa, ( ttl => 360, # sigval => 100, )); # Verify the just created signatures ok ($sigrsa->verify($datarrset,$rsakeyrr), 'DSA sig verifies'); my $sigrsasha1= create Net::DNS::RR::RRSIG($datarrset,$keypathrsasha1, ( ttl => 360, # sigval => 100, )); # Verify the just created signatures ok ($sigrsasha1->verify($datarrset,$rsasha1keyrr), 'DSA sig verifies'); } unlink($keypathrsa); unlink($keypathrsasha1); unlink($keypathdsa); Net-DNS-SEC-0.21/t/getpacket.pl0000755000175100017510000000065212422405404015334 0ustar willemwillem#!/usr/bin/perl -w # Just a little helper program to create the UUencoded packet data in # t/10-keyset. # # There is no real use for it except that you may look at the code. use strict; use Net::DNS::Resolver; my $res = Net::DNS::Resolver->new; $res->dnssec(1); $res->nameservers('10.0.53.203'); my $packet = $res->query ("sub.tld", "KEY", "IN"); $packet->print; my $Uencoded=unpack("H*",$packet->data); print $Uencoded; Net-DNS-SEC-0.21/t/00-pod.t0000644000175100017510000000072012422405404014205 0ustar willemwillem# $Id: 00-pod.t 813 2009-11-27 09:10:10Z olaf $ use Test::More; use File::Spec; use File::Find; use strict; eval "use Test::Pod 0.95"; if ($@) { plan skip_all => "Test::Pod v0.95 required for testing POD"; } else { Test::Pod->import; my @files; my $blib = File::Spec->catfile(qw(blib lib)); find( sub { push(@files, $File::Find::name) if /\.p(l|m|od)$/}, $blib); plan tests => scalar @files; foreach my $file (@files) { pod_file_ok($file); } } Net-DNS-SEC-0.21/t/05-NSEC3PARAM.t0000644000175100017510000000431612422405404015031 0ustar willemwillem# $Id: 05-NSEC3PARAM.t 1193 2014-04-28 07:11:19Z willem $ -*-perl-*- use strict; use Test::More tests => 16; use Net::DNS; my $name = 'example'; my $type = 'NSEC3PARAM'; my $code = 51; my @attr = qw( algorithm flags iterations salt ); my @data = qw( 1 0 12 aabbccdd ); my @also = qw( ); my $wire = '0100000c04aabbccdd'; { my $typecode = unpack 'xn', new Net::DNS::RR(". $type")->encode; is( $typecode, $code, "$type RR type code = $code" ); my $hash = {}; @{$hash}{@attr} = @data; my $rr = new Net::DNS::RR( name => $name, type => $type, %$hash ); my $string = $rr->string; my $rr2 = new Net::DNS::RR($string); is( $rr2->string, $string, 'new/string transparent' ); is( $rr2->encode, $rr->encode, 'new($string) and new(%hash) equivalent' ); foreach (@attr) { is( $rr->$_, $hash->{$_}, "expected result from rr->$_()" ); } foreach (@also) { is( $rr2->$_, $rr->$_, "additional attribute rr->$_()" ); } my $null = new Net::DNS::RR("$name NULL")->encode; my $empty = new Net::DNS::RR("$name $type")->encode; my $rxbin = decode Net::DNS::RR( \$empty )->encode; my $txtext = new Net::DNS::RR("$name $type")->string; my $rxtext = new Net::DNS::RR($txtext)->encode; my $encoded = $rr->encode; my $decoded = decode Net::DNS::RR( \$encoded ); my $hex1 = unpack 'H*', $encoded; my $hex2 = unpack 'H*', $decoded->encode; my $hex3 = unpack 'H*', substr( $encoded, length $null ); is( $hex2, $hex1, 'encode/decode transparent' ); is( $hex3, $wire, 'encoded RDATA matches example' ); is( length($empty), length($null), 'encoded RDATA can be empty' ); is( length($rxbin), length($null), 'decoded RDATA can be empty' ); is( length($rxtext), length($null), 'string RDATA can be empty' ); } { # check parsing of RR with null salt (RT#95034) my $rr = eval { Net::DNS::RR->new('nosalt.example NSEC3PARAM 2 0 12 -') }; diag $@ if $@; ok( $rr, 'NSEC3PARAM created with null salt' ); is( $rr->salt, '', 'NSEC3PARAM null salt value' ); is( unpack( 'H*', $rr->saltbin ), '', 'NSEC3PARAM null salt binary value' ); } { my $rr = eval { Net::DNS::RR->new('corrupt.example NSEC3PARAM 2 0 12 aabbccfs') }; ok( !$rr, 'NSEC3PARAM not created with corrupt hex data' ); } exit; Net-DNS-SEC-0.21/t/52-DS-SHA256.t0000644000175100017510000000206412422405404014611 0ustar willemwillem# $Id: 52-DS-SHA256.t 1137 2013-12-10 14:48:08Z willem $ use strict; BEGIN { use Test::More; plan tests => 5; use_ok('Net::DNS::SEC'); use_ok('Digest::SHA'); } # Simple known-answer tests based upon the examples given in RFC4509, section 2.3 my $dnskey = Net::DNS::RR->new( 'dskey.example.com. 86400 IN DNSKEY 256 3 5 ( AQOeiiR0GOMYkDshWoSKz9Xz fwJr1AYtsmx3TGkJaNXVbfi/ 2pHm822aJ5iI9BMzNXxeYCmZ DRD99WYwYqUSdjMmmAphXdvx egXd/M5+X7OrzKBaMbCVdFLU Uh6DhweJBjEVv5f2wwjM9Xzc nOf+EPbtG9DMBmADjFDc2w/r ljwvFw== ) ; key id = 60485' ); my $ds = Net::DNS::RR->new( 'dskey.example.com. 86400 IN DS 60485 5 2 ( D4B7D520E7BB5F0F67674A0C CEB1E3E0614B93C4F9E99B83 83F6A1E4469DA50A )' ); my $test = create Net::DNS::RR::DS( $dnskey, digtype => 'SHA256' ); is( $test->string, $ds->string, 'created DS matches RFC4509 example DS' ); ok( $test->verify($dnskey), 'created DS verifies RFC4509 example DNSKEY' ); ok( $ds->verify($dnskey), 'RFC4509 example DS verifies DNSKEY' ); $test->print; __END__ Net-DNS-SEC-0.21/t/05-DLV.t0000644000175100017510000000322512422405404014060 0ustar willemwillem# $Id: 05-DLV.t 1137 2013-12-10 14:48:08Z willem $ -*-perl-*- use strict; use Test::More tests => 13; use Net::DNS; my $name = 'DLV.example'; my $type = 'DLV'; my $code = 32769; my @attr = qw( keytag algorithm digtype digest ); my @data = ( 42495, 5, 1, '0ffbeba0831b10b8b83440dab81a2148576da9f6' ); my @also = qw( digestbin babble ); my $wire = join '', qw( A5FF 05 01 0FFBEBA0831B10B8B83440DAB81A2148576DA9F6 ); { my $typecode = unpack 'xn', new Net::DNS::RR(". $type")->encode; is( $typecode, $code, "$type RR type code = $code" ); my $hash = {}; @{$hash}{@attr} = @data; my $rr = new Net::DNS::RR( name => $name, type => $type, %$hash ); my $string = $rr->string; my $rr2 = new Net::DNS::RR($string); is( $rr2->string, $string, 'new/string transparent' ); is( $rr2->encode, $rr->encode, 'new($string) and new(%hash) equivalent' ); foreach (@attr) { is( $rr->$_, $hash->{$_}, "expected result from rr->$_()" ); } foreach (@also) { is( $rr2->$_, $rr->$_, "additional attribute rr->$_()" ); } my $empty = new Net::DNS::RR("$name $type"); my $encoded = $rr->encode; my $decoded = decode Net::DNS::RR( \$encoded ); my $hex1 = uc unpack 'H*', $decoded->encode; my $hex2 = uc unpack 'H*', $encoded; my $hex3 = uc unpack 'H*', substr( $encoded, length $empty->encode ); is( $hex1, $hex2, 'encode/decode transparent' ); is( $hex3, $wire, 'encoded RDATA matches example' ); $rr->algorithm('RSASHA512'); is( $rr->algorithm(), 10, 'algorithm mnemonic accepted' ); $rr->digtype('SHA256'); is( $rr->digtype(), 2, 'digest type mnemonic accepted' ); } { my $rr = new Net::DNS::RR("$name $type @data"); $rr->print; } exit; Net-DNS-SEC-0.21/t/05-KEY.t0000644000175100017510000000353312422405404014065 0ustar willemwillem# $Id: 05-KEY.t 1141 2013-12-16 15:10:15Z willem $ -*-perl-*- use strict; use Test::More tests => 16; use Net::DNS; my $name = 'KEY.example'; my $type = 'KEY'; my $code = 25; my @attr = qw( flags protocol algorithm publickey ); my @data = ( 256, 3, 5, join '', qw( AQPSKmynfzW4kyBv015MUG2DeIQ3 Cbl+BBZH4b/0PY1kxkmvHjcZc8no kfzj31GajIQKY+5CptLr3buXA10h WqTkF7H6RfoRqXQeogmMHfpftf6z Mv1LyBUgia7za6ZEzOJBOztyvhjL 742iU/TpPSEDhm2SNKLijfUppn1U aNvv4w== ) ); my @also = qw( keybin keylength keytag privatekeyname zone revoke sep ); my $wire = join '', qw( 010003050103D22A6CA77F35B893206FD35E4C506D8378843709B97E041647E1 BFF43D8D64C649AF1E371973C9E891FCE3DF519A8C840A63EE42A6D2EBDDBB97 035D215AA4E417B1FA45FA11A9741EA2098C1DFA5FB5FEB332FD4BC8152089AE F36BA644CCE2413B3B72BE18CBEF8DA253F4E93D2103866D9234A2E28DF529A6 7D5468DBEFE3 ); { my $typecode = unpack 'xn', new Net::DNS::RR(". $type")->encode; is( $typecode, $code, "$type RR type code = $code" ); my $hash = {}; @{$hash}{@attr} = @data; my $rr = new Net::DNS::RR( name => $name, type => $type, %$hash ); my $string = $rr->string; my $rr2 = new Net::DNS::RR($string); is( $rr2->string, $string, 'new/string transparent' ); is( $rr2->encode, $rr->encode, 'new($string) and new(%hash) equivalent' ); foreach (@attr) { is( $rr->$_, $hash->{$_}, "expected result from rr->$_()" ); } foreach (@also) { is( $rr2->$_, $rr->$_, "additional attribute rr->$_()" ); } my $empty = new Net::DNS::RR("$name NULL"); my $encoded = $rr->encode; my $decoded = decode Net::DNS::RR( \$encoded ); my $hex1 = uc unpack 'H*', $decoded->encode; my $hex2 = uc unpack 'H*', $encoded; my $hex3 = uc unpack 'H*', substr( $encoded, length $empty->encode ); is( $hex1, $hex2, 'encode/decode transparent' ); is( $hex3, $wire, 'encoded RDATA matches example' ); } exit; Net-DNS-SEC-0.21/t/51-DS-SHA1.t0000644000175100017510000000152112422405404014431 0ustar willemwillem# $Id: 51-DS-SHA1.t 1137 2013-12-10 14:48:08Z willem $ use strict; BEGIN { use Test::More; plan tests => 5; use_ok('Net::DNS::SEC'); use_ok('Digest::SHA'); } # Simple known-answer tests based upon the examples given in RFC3658, section 2.7 my $key = Net::DNS::RR->new( 'dskey.example. KEY 256 3 1 ( AQPwHb4UL1U9RHaU8qP+Ts5bVOU1s7fYbj2b3CCbzNdj 4+/ECd18yKiyUQqKqQFWW5T3iVc8SJOKnueJHt/Jb/wt ) ; key id = 28668' ); my $ds = Net::DNS::RR->new( 'dskey.example. DS 28668 1 1 49FD46E6C4B45C55D4AC69CBD3CD34AC1AFE51DE' ); my $test = create Net::DNS::RR::DS( $key, digtype => 'SHA1', ); is( $test->string, $ds->string, 'created DS matches RFC3658 example DS' ); ok( $test->verify($key), 'created DS verifies RFC3658 example KEY' ); ok( $ds->verify($key), 'RFC3658 example DS verifies example KEY' ); $test->print; __END__ Net-DNS-SEC-0.21/t/10-typeroll.t0000644000175100017510000003355012422405404015305 0ustar willemwillem#!/usr/bin/perl -sw # Test script for dnssec functionalty # $Id: 10-typeroll.t 1192 2014-04-11 08:43:54Z willem $ # # Called in a fashion simmilar to: # /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-freebsd \ # -I/usr/lib/perl5/5.6.1 -e 'use Test::Harness qw(&runtests $verbose); \ # $verbose=0; runtests @ARGV;' t/10-typeroll.t use Test::More tests=>38; use strict; BEGIN { use_ok('Net::DNS::SEC'); } # test 1 my $datarrset; my ($datarr1, $datarr2, $datarr3); my $datastring1="test.tld. 7000 IN NS ns.test.tld."; my $datastring2="test.tld. 7000 IN NS ns.foo.tld."; my $datastring3="test.tld. 7000 IN NS ns.boo.tld."; $datarr1= new Net::DNS::RR($datastring1); ok ( $datarr1, 'data RR 1 loaded '); # test 2 $datarr2= new Net::DNS::RR($datastring2); ok ( $datarr2, 'data RR 2 loaded '); # test 3 $datarr3= new Net::DNS::RR($datastring3); ok ( $datarr3, 'data RR 3 loaded '); # test 4 $datarrset = [ $datarr1, $datarr2 , $datarr3 ] ; ############################################## # In the following tests we first sign a DNSKEY and then verify it again. # We do this for both RSA and DSA. # This is a consistency check # # The private key will be written to disk first. # # Keypairs generated with dnssec-keygen. (9.2.0rc1) # # RSA keypair # my $keypathrsa="Ktest.tld.+001+11567.private"; my $privrsakey= << 'ENDRSA' ; Private-key-format: v1.2 Algorithm: 1 (RSA) Modulus: 6ASwF3rSBFnBBQ7PmdWJnNkT2XkbZP5Be28SyTohsnuT1Rw7OlbNVNiT+4S04JUS0itVbvgtYmDZGMU3nfZP+er20uJRo/mu6hSkJW3MX5ES8o/GnOST1zSCH1+aA1Y6AlhfLebC+ysVKftLYnEco6oHNioYOmYHozYr5d0tL/s= PublicExponent: Aw== PrivateExponent: mq3KulHhWDvWA181ETkGaJC35lC87f7WUkoMhibBIae342gnfDneOJBip63N6w4MjBzjn1AeQZXmEIN6aU7f+q0Fwsyl4FzrSa8ehjfTS4u4YZE/Zk9rv0VIZuYwyccgLEBLYNBYRLbkbuSqDspw+Th8dCGy7XZ06eRkGZSNMjs= Prime1: 9Fssra0OAl4kNX105Xdrnb7kS+/6QgWeJeBJCuajjWQ0uRiEClDzjVVVr6BW2DixP+6RCbSDioSIqsNc546UtQ== Prime2: 8xMCAavFa+/XWHjnNJgCob976feJK2yaJrU7+2oxHiWLPtWYo+2gi2kt9Kv1aTp8lV327ddSqdO7tNJilsrP7w== Exponent1: oudzHnNerD7CzlOjQ6TyaSnth/VRgVkUGUAwse8Xs5gjJhBYBuCiXjjjymrkkCXLf/RgsSMCXFhbHII977RjIw== Exponent2: ogysAR0uR/U6OvtEzbqsa9T9RqUGHPMRbyN9UkbLaW5c1I5lwp5rB5tz+HKjm3xTDj6kno+McTfSeIxBudyKnw== Coefficient: Cxwv14w+KY7rmiO4U0giXqOij9gON7TiByj5dQjHGUQdaQEJ0zK2SlxouEfgi3hcxTGI753pFmW0cF/MDjFURw== ENDRSA my $rsakeyrr=new Net::DNS::RR ("test.tld. IN DNSKEY 256 3 1 AQPoBLAXetIEWcEFDs+Z1Ymc2RPZeRtk/kF7bxLJOiGye5PVHDs6Vs1U 2JP7hLTglRLSK1Vu+C1iYNkYxTed9k/56vbS4lGj+a7qFKQlbcxfkRLy j8ac5JPXNIIfX5oDVjoCWF8t5sL7KxUp+0ticRyjqgc2Khg6ZgejNivl 3S0v+w== "); ok( $rsakeyrr, 'RSA public key created'); # test 5 my $keypathdsa="Ktest.tld.+003+09734.private"; my $privdsakey= << 'ENDDSA' ; Private-key-format: v1.2 Algorithm: 3 (DSA) Prime(p): 7m5wm/8KMO1fLaBB2Wbq3s0/jMudrauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/joY2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srlslykC+LQRnsbxB5YJMgmkPaPZU8GpRcc= Subprime(q): jRgd5fwOUwUmNpcD6Uzs/tMzy3U= Base(g): a0/+JhZhnci+P8/GOvnokG3NAF10o0Pf6/oz5UpcmX89KqjPvn9aRTRI9sM2AJgFBkzrQhXcx9NPvhneW0zN/baQhaUkupJ8YazNkkVKfOM6aH9h8ONVgGNRiLEBILQa07EMzce9/+JDYFbOCajJqhb9MZlTau17GDDK+r4okJ0= Private_value(x): C7O98kp8pfDdqeuvD83nf1xc4sI= Public_value(y): kFKU1HfmfRxPWwS9mA3FBHZ9LbmEizsH7vFSD7m31crIDVpxIO02bhKyFAuurKNh6naG4iTo3ak0yv6/bP8VNFIxN2QHPnnQL72ctUpvMLe+kWX7fGXuXWPIUCWVnbAeP2SnxpjxU039E9A2Rk6Dp9Eu0oXsM8hcUUnRv6ekycA= ENDDSA open (RSA,">$keypathrsa") or die "Could not open $keypathrsa"; print RSA $privrsakey; close(RSA); my $dsakeyrr=new Net::DNS::RR ("test.tld. IN DNSKEY 256 3 3 CI0YHeX8DlMFJjaXA+lM7P7TM8t17m5wm/8KMO1fLaBB2Wbq3s0/jMud rauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/jo Y2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srls lykC+LQRnsbxB5YJMgmkPaPZU8GpRcdrT/4mFmGdyL4/z8Y6+eiQbc0A XXSjQ9/r+jPlSlyZfz0qqM++f1pFNEj2wzYAmAUGTOtCFdzH00++Gd5b TM39tpCFpSS6knxhrM2SRUp84zpof2Hw41WAY1GIsQEgtBrTsQzNx73/ 4kNgVs4JqMmqFv0xmVNq7XsYMMr6viiQnZBSlNR35n0cT1sEvZgNxQR2 fS25hIs7B+7xUg+5t9XKyA1acSDtNm4SshQLrqyjYep2huIk6N2pNMr+ v2z/FTRSMTdkBz550C+9nLVKbzC3vpFl+3xl7l1jyFAllZ2wHj9kp8aY 8VNN/RPQNkZOg6fRLtKF7DPIXFFJ0b+npMnA "); ok( $dsakeyrr, 'RSA public key created'); # test 6 open (DSA,">$keypathdsa") or die "Could not open $keypathdsa"; print DSA $privdsakey; close(DSA); # Create the signature records. my $sigrsa= create Net::DNS::RR::RRSIG($datarrset,$keypathrsa, ( ttl => 360, # sigval => 100, )); ok ( $sigrsa, 'RSA signature created'); # test 7 my $sigdsa= create Net::DNS::RR::RRSIG($datarrset,$keypathdsa, ( ttl => 360, # sigval => 100, )); ok ( $sigdsa, 'DSA signature created'); # test 8 # Verify the just created signatures ok ($sigrsa->verify($datarrset,$rsakeyrr),'RSA sig verifies'); # test 9 # Verify the just created signatures ok ($sigdsa->verify($datarrset,$dsakeyrr), 'DSA sig verifies'); # test 10 # on the other hand checking against the wrong key should fail. ok (! $sigrsa->verify($datarrset,$dsakeyrr), 'RSA sig fails against corrupt data'); # test 11 ok (! $sigdsa->verify($datarrset,$rsakeyrr), 'DSA sig fails against corrupt data'); # test 12 # Now corrupt the key and test again.. that should fail # Corruption is very hard to notice.. we modified one letter # in the base 64 representation. my $corrupt_rsakeyrr=new Net::DNS::RR ("test.tld. IN DNSKEY 256 3 1 AQOi+0LmBAfV+4CdCoy81y0Z9fejYXzbXrh87u2gaJZ12ItO5bGtegfA ykgUs76ElH1fGvWBpaHqh3roImc7MGkhCMh7+G2lE7aeYsUXn5wHdBFE wZBaards8JcMEcT8nHyKHNZlq9fAhQ36guqGdZuRPqxgYfwz71VJb2t9 6KX/5w=="); ok (!$sigrsa->verify($datarrset,$corrupt_rsakeyrr),'RSA fails against corrupt key'); # test 13 my $corrupt_dsakeyrr=new Net::DNS::RR ("test.tld. IN DNSKEY 256 3 3 CI0YHeX8DlMFJjaXA+lM7P7TM8t17m5wm/8KMO1fLaBB2Wbq3s0/jMue rauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/jo Y2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srls lykC+LQRnsbxB5YJMgmkPaPZU8GpRcdrT/4mFmGdyL4/z8Y6+eiQbc0A XXSjQ9/r+jPlSlyZfz0qqM++f1pFNEj2wzYAmAUGTOtCFdzH00++Gd5b TM39tpCFpSS6knxhrM2SRUp84zpof2Hw41WAY1GIsQEgtBrTsQzNx73/ 4kNgVs4JqMmqFv0xmVNq7XsYMMr6viiQnZBSlNR35n0cT1sEvZgNxQR2 fS25hIs7B+7xUg+5t9XKyA1acSDtNm4SshQLrqyjYep2huIk6N2pNMr+ v2z/FTRSMTdkBz550C+9nLVKbzC3vpFl+3xl7l1jyFAllZ2wHj9kp8aY 8VNN/RPQNkZOg6fRLtKF7DPIXFFJ0b+npMnA"); ok (! $sigdsa->verify($datarrset,$corrupt_dsakeyrr),'DSA fails against corrupt key'); # test 14 # Now test some DSA stuff my $dsrr=create Net::DNS::RR::DS($rsakeyrr); ok( $dsrr,'DS created from DNSKEY RR'); # test 15 ok( $dsrr->verify($rsakeyrr),'DS matches DNSKEY'); # test 16 my $dsrr2=Net::DNS::RR->new("test.tld. 0 IN DS 42495 1 1 0ffbeba0831b10b8b83440dab81a2148576da9f6"); ok( $dsrr,'DS(2) created from string'); # test 17 ok( $dsrr->verify($rsakeyrr),'DS(2) matches DNSKEY'); # test 18 my ($nlkey1, $nlsig1, $nlNS1, $nlNS2, $nlNS3, $nldatarrset); $nlNS1=new Net::DNS::RR(" host100.ws.disi. 600 IN A 10.1.1.100"); $nlNS2=new Net::DNS::RR("host100.ws.disi. 600 IN A 10.1.2.100"); $nlNS3=new Net::DNS::RR("host100.ws.disi. 600 IN A 10.1.3.100"); $nldatarrset=[$nlNS1,$nlNS3, $nlNS2]; my $dsasigrr=Net::DNS::RR::RRSIG->create($nldatarrset, $keypathdsa ); ok( $dsasigrr, 'DSA signature with bind generated key'); # test 19 my $rsasigrr=Net::DNS::RR::RRSIG->create($nldatarrset, $keypathrsa ); ok( $rsasigrr, 'RSA signature with bind generated key'); # test 20 ok( $dsasigrr->verify($nldatarrset,$dsakeyrr),'DSA sig (test 2) verifies'); # test 21 is( $dsasigrr->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); # test 22 ok( $rsasigrr->verify($nldatarrset,$rsakeyrr),'RSA sig (test 2) verifies'); is( $rsasigrr->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); # test 24 # # SOA with escaped dot. $datarr1 = Net::DNS::RR->new("test.tld. 7000 IN SOA ( ns.test.tld. first\.last.test.tld. 2002042603 43200 7200 1209600 7200)"); $datarrset = [ $datarr1 ] ; $sigrsa= create Net::DNS::RR::RRSIG($datarrset,$keypathrsa, ( ttl => 360, # sigval => 100, )); ok ( $sigrsa, 'RSA signature over SOA with escaped dot created'); #test 25 ok ($sigrsa->verify($datarrset,$rsakeyrr),'RSA sig over SOA with escaped dot verifies'); #test 26 # clean the private key files (not needed no more) # Cross check with a signature generated with bind tools. #test fails after October 2030 : my $bindkey=Net::DNS::RR->new("netdns.work. 900 DNSKEY 257 3 5 ( AQOwktT7a2gfGNXWK+QWKP/Lln5Z/fSz0q2f R1fA4QBQsWsrnKz/yqXRmOHhf8X975ZVwpdo 456wYjbfrP03sSjI3Wj9y5Mnr09HUUaBdwF/ 7VVgpP8Mgwe3FJ4f2uPwBFm2/+7+wxMyjIbL mu0Ec6xtZtEARe99RLnRCnF1gXb6Uw== ) ; key id = 17895"); my $bindsig=Net::DNS::RR->new("netdns.work. 900 RRSIG DNSKEY 5 2 900 20350101000000 ( 20040121160223 17895 netdns.work. SUENn9MMZd9PPdtt//rbMbCgI7XGAmvb4QWO 6Zuwis3ErhZR5PdiQNqhY53pN44Dnq5Qv4CO nIpoFLMZKpT1W/8jNFHZI8wX63hn8kYDUW9C lJt2YlovakAo3tMR3L/QvbkentB3ljJVEMYF PwJCmzS64bXNr960ZlOfnKY4Yl8= )"); my $binddataset=[$bindkey]; my $nsecrr = Net::DNS::RR->new("example.com 7200 NSEC bert.example.com. NS SOA MX TXT LOC RRSIG NSEC DNSKEY"); ok ( $nsecrr, 'NSEC RR created from string'); #test 27 my $nsecsig = Net::DNS::RR->new("example.com 7200 RRSIG NSEC 5 2 7200 20310101000000 ( 20040126131948 37790 example.com. IFK3Y4xZwkyHP0TwMnsC7g2IvHRZmsk8rFH7 l1dM7Jyb7+p2Mh1nm13vv56sBOItHNDGvQtN yVDNuG2brf0zpHLHSzB/KsW1NNLTrTCscK1W 0JNu2WwiZo62dZLQqIY4RQqTsWxf17c0f3aA w8ogGRXVnHwv0uGKRfMnWpX2AgA= )"); my $nseckey = Net::DNS::RR->new("example.com 900 DNSKEY 256 3 5 ( AQOzkktb0iNYIj9GuasRjJixkK/YZ5eAe/Hs anvfZ7023ZPmEdNvRfygmCRDOFs0ud7J8u8n YnWn9EBxxS4AKSj8To+Dtx+vuW/g72SQjbNZ T3EGlwU3F2455qUAkAd4CADVMcbbLO0MbXRk /fd+Mq8A1zdX8q602fdaxaZ325nE0Q== )"); my @nsecdata = ($nsecrr); SKIP: { skip "Test material not available yet, will be fixed in later release", 2 if 0; ok( $bindsig->verify( $binddataset, $bindkey ), 'RSA sig generated with bind verifies'); #test 28 ok( $nsecsig->verify( \@nsecdata, $nseckey ), "RRSIG over NSEC verifies"); #test 29 } # # RSA keypair # my $keypathrsasha1="Ktest.tld.+005+29159.private"; my $privrsakeysha1= << 'ENDRSA' ; Private-key-format: v1.2 Algorithm: 5 (RSA-SHA1) Modulus: ovtC5gQH1fuAnQqMvNctGfX3o2F82164fO7toGiWddiLTuWxrXoHwcpIFLO+hJR9Xxr1gaWh6od66CJnOzBpIQjIe/htpRO2nmLFF5+cB3QRRMGQWmq3bPCXDBHE/Jx8ihzWZavXwIUN+oLqhnWbkT6sYGH8M+9VSW9rfeil/+c= PublicExponent: Aw== PrivateExponent: bKeB7q1ajqerE1xd0zoeEU6lF5ZTPOnQU0nzwEW5o+WyNJkhHlFagTGFYyJ/Aw2o6hH5ARkWnFpR8BbvfMrwv6AeCrahtJgilCpCYxwusOOikbkGR/sXP5ObscRmEuhfzVYBV62yMc34MyspHzXHNZAL+SgRswopy6MgWdAII2s= Prime1: 0GNRLAYLvgaIZ+8o/fVST6WEhQd4bDIEHnBtIxHj9NIrHL/nIerA80sth+Pwfed2zp109U+zvcizUSfJDbHRsQ== Prime2: yDgaunUKcXw3u3JZ92Crzvflpv92BeKJdL0USBn8Sxqq/xR7BWG03M6AOkjnJwlKF/z1sJHzok3kqZMuIuf5Fw== Exponent1: iuzgyAQH1ARa7/TF/qOMNRkDA1pQSCFYFErzbLaX+IwcvdVEwUcrTNzJBUKgU++kib5N+N/NKTB3i2/bXnaLyw== Exponent2: hXq8fE4G9lLP0kw7+kByifqZGf+kA+xboyi4MBFS3Lxx/2L8rkEjPd8AJttExLDcD/35IGFNFt6YcQzJbJqmDw== Coefficient: gAeUUI6YOtdNAh3kS7pOzYfn0ZrUCV8bGpZoaXANk2RL2zUiaSSa4wudhpHwMJt+psNkkiQyf4v600uHbxro4Q== ENDRSA my $rsasha1keyrr=new Net::DNS::RR ("test.tld. IN DNSKEY 256 3 5 AQOi+0LmBAfV+4CdCoy81y0Z9fejYXzbXrh87u2gaJZ12ItO5bGtegfB ykgUs76ElH1fGvWBpaHqh3roImc7MGkhCMh7+G2lE7aeYsUXn5wHdBFE wZBaards8JcMEcT8nHyKHNZlq9fAhQ36guqGdZuRPqxgYfwz71VJb2t9 6KX/5w=="); ok( $rsasha1keyrr, 'RSA-SHA1 public key created'); #test 30 open (RSA,">$keypathrsasha1") or die "Could not open $keypathrsasha1"; print RSA $privrsakeysha1; close(RSA); my $sigrsasha1= create Net::DNS::RR::RRSIG($datarrset,$keypathrsasha1, ( ttl => 360, # sigval => 100, )); ok ( $sigrsasha1, 'RSA SHA1 signature created'); #test 31 ok ($sigrsasha1->verify($datarrset,$rsasha1keyrr),'RSA SHA1 sig verifies'); #test 32 ### Test usability of the private key object.. same set of test as above my $dsaprivate=Net::DNS::SEC::Private->new($keypathdsa); my $dsasigrr_p=Net::DNS::RR::RRSIG->create($nldatarrset, $dsaprivate ); ok( $dsasigrr_p, 'DSA signature with bind generated key '); # test 33 my $rsaprivate=Net::DNS::SEC::Private->new($keypathrsa); my $rsasigrr_p=Net::DNS::RR::RRSIG->create($nldatarrset, $rsaprivate ); ok( $rsasigrr_p, 'RSA signature with bind generated key'); # test 34 ok( $dsasigrr_p->verify($nldatarrset,$dsakeyrr),'DSA sig (test 2) verifies'); # test 35 is( $dsasigrr_p->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); # test 36 ok( $rsasigrr_p->verify($nldatarrset,$rsakeyrr),'RSA sig (test 2) verifies'); is( $rsasigrr_p->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); # test 38 unlink($keypathrsa); unlink($keypathdsa); unlink($keypathrsasha1); Net-DNS-SEC-0.21/t/13-utilities.t0000644000175100017510000001135112422405404015444 0ustar willemwillem#!/usr/bin/perl -sw # Test script for dnssec functionalty # $Id: 13-utilities.t 1170 2014-02-10 10:42:45Z willem $ # # Called in a fashion simmilar to: # /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-freebsd \ # -I/usr/lib/perl5/5.6.1 -e 'use Test::Harness qw(&runtests $verbose); \ # $verbose=0; runtests @ARGV;' t/13-utilities use Test::More tests=>6; use strict; use Net::DNS::Keyset; use Net::DNS::SEC qw( key_difference); my $rr; my @keyrr; my @keyrr2; my @sigrr; # Note that the order on pushing the RRsigs is important for # succesfully testing. # All signatures have expiration date in 2030... this test should work for a while $rr=Net::DNS::RR->new("example.com 100 IN DNSKEY 256 3 5 ( AQOxFlzX8vShSG3JG2J/fngkgy64RoWr8ovG e7MuvPJqOMHTLM5V8+TJIahSoyUd990ictNv hDegUqLtZ8k5oQq44viFCU/H1apdEaJnLnXs cVo+08ATlEb90MYznK9K0pm2ixbyspzRrrXp nPi9vo9iU2xqWqw/Efha4vfi6QVs4w== ) "); push(@keyrr,$rr); push(@keyrr2,$rr); $rr=Net::DNS::RR->new("example.com 100 IN DNSKEY 256 3 5 ( AQO4jhl6ilWV2mYjwWl7kcxrYyQsnnbV7pxX m48p+SgAr+R5SKyihkjg86IjZBQHFJKZ8RsZ dhclH2dikM+53uUEhrqVGhsqF8FsNi4nE9aM ISiX9Zs61pTYGYboYDvgpD1WwFbD4YVVlfk7 rCDP/zOE7H/AhkOenK2w7oiO0Jehcw== ) "); push(@keyrr,$rr); push(@keyrr2,$rr); my $poppedkey=Net::DNS::RR->new($rr->string); $rr=Net::DNS::RR->new("example.com 100 IN DNSKEY 256 3 5 ( AQO5fWabr7bNxDXT8YrIeclI9nvYYdKni3ef gJfU749O3QVX9MON6WK0ed00odQF4cLeN3vP SdhasLDI3Z3TzyAPBQS926oodxe78K9zwtPT 1kzJxvunOdJr6+6a7/+B6rF/cwfWTW50I0+q FykldldB44a1uS34u3HgZRQXDmAesw== ) "); push(@keyrr,$rr); push(@keyrr2,$rr); $rr=Net::DNS::RR->new("example.com 100 IN DNSKEY 256 3 5 ( AQO6uGWsox2oH36zusGA0+w3uxkZMdByanSC jiaRHtkOA+gIxT8jmFvohxQBpVfYD+xG2pt+ qUWauWPFPjsIUBoFqHNpqr2/B4CTiZm/rSay HDghZBIMceMa6t4NpaOep79QmiE6oGq6yWRB swBkPZx9uZE7BqG+WLKEp136iwWyyQ== ) "); push(@keyrr,$rr); push(@keyrr2,$rr); $rr=Net::DNS::RR->new("example.com 100 IN RRSIG DNSKEY 5 2 100 20300101000000 ( 20040601105519 11354 example.com. GTqyJTRbKJ0LuWbAnNni1M4JZ1pn+nXY1Zuz Z0Kvt6OMTYCAFMFt0Wv9bncYkUuUSMGM7yGG 9Z7g7tcdb4TKCqQPYo4gr3Qj/xgC4LESoQs0 yAsJtLUiDfO6e4aWHmanpMGyGixYzHriS1pt SRzirL1fTgV+kdNs5zBatUHRnQc=) "); push(@sigrr,$rr); $rr=Net::DNS::RR->new("example.com 100 IN RRSIG DNSKEY 5 2 100 20300101000000 ( 20040601105519 28109 example.com. WemQqA+uaeKqCy6sEVBU3LDORG3f+Zmix6qK 9j1WL83UMWdd6sxNh0QJ0YL54lh9NBx+Viz7 gajO+IM4MmayxKY4QVjp+6mHeE5zBVHMpTTu r5T0reNtTsa8sHr15fsI49yn5KOvuq+DKG1C gI6siM5RdFpDsS3Rmf8fiK1PyTs= )"); push(@sigrr,$rr); $rr=Net::DNS::RR->new("example.com 100 IN RRSIG DNSKEY 5 2 100 20300101000000 ( 20040601105519 33695 example.com. M3yVwTOMw+jAKYY5c6oS4DH7OjOdfMOevpIe zdKqWXkehoDg9YOwz8ai17AmfgkjZnsoNu0W NMIcaVubR3n02bkVhJb7dEd8bhbegF8T1xkL 7rf9EQrPmM5GhHmVC90BGrcEhe//94hdXSVU CRBi6KPFWSZDldd1go133bk/b/o= )"); push(@sigrr,$rr); $rr=Net::DNS::RR->new("example.com 100 IN RRSIG DNSKEY 5 2 100 20300101000000 ( 20040601105519 39800 example.com. Mmhn2Ql6ExmyHvZFWgt+CBRw5No8yM0rdH1b eU4is5gRbd3I0j5z6PdtpYjAkWiZNdYsRT0o P7TQIsADfB0FLIFojoREg8kp+OmbpRTsLTgO QYC95u5WodYGz03O0EbnQ7k4gkje6385G40D JVl0xVfujHBMbB+keiSphD3mG4I= )"); push(@sigrr,$rr); # # Test key_difference function from Net::DNS::SEC # # @keyrr and @keyrr2 contain exactly the same data, we'll now add two different # keys to @keyrr2 and to an array to compare the results against. my @result; my @testresult; $rr=Net::DNS::RR->new("example.com. IN DNSKEY 256 3 5 AQOxZqVCFGc1pNh8TVnxPwcEauBXgxKFOc9stE/aKCQP/2vFE7N2agu+ /LlQlTmKFWLaGfJnVazLDEFi3Fp4PK1Z"); push(@keyrr2,$rr); push(@testresult,$rr); $rr=Net::DNS::RR->new("example.com. IN DNSKEY 256 3 5 AQOURUjSxNm1X5wIfSzUHWl8kOpVwCFVaCpn/qrIrdOMTetNA1M3Ph4g xaH+JNxYETFw+cH9ZZqhawd95mON1HJv"); push(@keyrr2,$rr); push(@testresult,$rr); ok(!key_difference(\@keyrr2,\@keyrr,\@result), "key_difference returns 0 as return code"); #test 1 ok( eq_array(\@result,\@testresult),"key_difference fills the return array with correct values"); # test 2 my $unexpected = Net::DNS::RR->new("example.com IN A 10.0.0.1"); my $erroneous = ref $unexpected; my @keyrrx = ( @keyrr2, $unexpected ); my $error1 = key_difference( \@keyrrx, \@keyrr, \@result ); ok( $error1 =~ /$erroneous/, "key_difference() detects $erroneous object in argument 1" ); # test 3 my $error2 = key_difference( \@keyrr, \@keyrrx, \@result ); ok( $error2 =~ /$erroneous/, "key_difference() detects $erroneous object in argument 2" ); #test 4 @result=(); ok( !key_difference(\@keyrr,\@keyrr2,\@result), "key_difference returns 0 as return code"); # test 5 is (@result,0,"key_difference returned empty array when 1st array is subset of 2nd"); # test 6 Net-DNS-SEC-0.21/t/Kexample.com.+001+28551.key0000644000175100017510000000032312422405404017107 0ustar willemwillemexample.com. IN DNSKEY 256 3 1 AQPR6/oBmgGL77vj0xrgfEaf3pSaJlr+BvxkU8O+Vqcz9dpCDTtsv6BJ 2E6tt+XZ9VgqFtQjhe4gI3dAZ5Wu/xvGqq2BfCExPQxLxG17Nt8iTlu7 NpR9jc+FHFjmRPMyvCE9/iknk7kiwek1ttvv0tNzVKZlWJDC8JUATrFX pm+HCQ== Net-DNS-SEC-0.21/t/Kexample.com.+005+34247.key0000644000175100017510000000032312422405404017112 0ustar willemwillemexample.com. IN DNSKEY 256 3 5 AQOqyylc732/AE42mlUE3g44JS3O4tdvUwOK3lwpQ/xOJX6gFLEg/SRK 36FXnXqbJzkqCkwVrCgbA2SM63axme57vbbnppljuiCKf6rxZE2602Yh OLPdsw+1nRRyHZ8fPv761H8bPS9Zcx3IQyE33l1B+tPN9MtQus6fcsQy 2tIwuw== Net-DNS-SEC-0.21/t/53-DS-GOST.t0000644000175100017510000000201512422405404014512 0ustar willemwillem# $Id: 53-DS-GOST.t 1137 2013-12-10 14:48:08Z willem $ use strict; BEGIN { use Test::More; plan skip_all => 'optional Digest::GOST not installed' unless eval { require Digest::GOST; }; plan tests => 5; use_ok('Net::DNS::SEC'); use_ok('Digest::GOST'); } # Simple known-answer tests based upon the examples given in RFC5933, section 4.1 my $dnskey = Net::DNS::RR->new( 'example.net. 86400 DNSKEY 257 3 12 ( LMgXRHzSbIJGn6i16K+sDjaDf/k1o9DbxScO gEYqYS/rlh2Mf+BRAY3QHPbwoPh2fkDKBroF SRGR7ZYcx+YIQw== ) ; key id = 40692' ); my $ds = Net::DNS::RR->new( 'example.net. 3600 IN DS 40692 12 3 ( 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B 2071398F )' ); my $test = create Net::DNS::RR::DS( $dnskey, digtype => 'GOST', ttl => 3600 ); is( $test->string, $ds->string, 'created DS matches RFC5933 example DS' ); ok( $test->verify($dnskey), 'created DS verifies RFC5933 example DNSKEY' ); ok( $ds->verify($dnskey), 'RFC5933 example DS verifies DNSKEY' ); $test->print; __END__ Net-DNS-SEC-0.21/t/05-SIG.t0000644000175100017510000000475212422405404014063 0ustar willemwillem# $Id: 05-SIG.t 1165 2014-01-20 14:06:08Z willem $ -*-perl-*- use strict; use Test::More tests => 18; use Net::DNS; my $name = 'net-dns.org'; my $type = 'SIG'; my $code = 24; my @attr = qw( typecovered algorithm labels orgttl sigexpiration siginception keytag signame signature ); my @data = ( qw( NS 7 2 3600 20130914141655 20130815141655 60909 net-dns.org ), join '', qw( IRlCjYNZCkddjoFw6UGxAga/EvxgENl+IESuyRH9vlrys yqne0gPpclC++raP3+yRA+gDIHrMkIwsLudqod4iuoA73 Mw1NxETS6lm2eQTDNzLSY6dnJxZBqXypC3Of7bF3UmR/G NhcFIThuV/qFq+Gs+g0TJ6eyMF6ydYhjS31k= ) ); my @also = qw( sigbin ); my $wire = '0002070200000E1052346FD7520CE2D7EDED076E65742D646E73036F7267002119428D83590A475D8E8170E941B10206BF12FC6010D97E2044AEC911FDBE5AF2B32AA77B480FA5C942FBEADA3F7FB2440FA00C81EB324230B0BB9DAA87788AEA00EF7330D4DC444D2EA59B67904C33732D263A767271641A97CA90B739FEDB17752647F18D85C1484E1B95FEA16AF86B3E8344C9E9EC8C17AC9D6218D2DF59'; { my $typecode = unpack 'xn', new Net::DNS::RR(". $type")->encode; is( $typecode, $code, "$type RR type code = $code" ); my $hash = {}; @{$hash}{@attr} = @data; my $rr = new Net::DNS::RR( name => $name, type => $type, %$hash ); my $string = $rr->string; my $rr2 = new Net::DNS::RR($string); is( $rr2->string, $string, 'new/string transparent' ); is( $rr2->encode, $rr->encode, 'new($string) and new(%hash) equivalent' ); foreach (@attr) { is( $rr->$_, $hash->{$_}, "expected result from rr->$_()" ); } foreach (@also) { is( $rr2->$_, $rr->$_, "additional attribute rr->$_()" ); } my $empty = new Net::DNS::RR("$name $type"); my $encoded = $rr->encode; my $decoded = decode Net::DNS::RR( \$encoded ); my $hex1 = uc unpack 'H*', $decoded->encode; my $hex2 = uc unpack 'H*', $encoded; my $hex3 = uc unpack 'H*', substr( $encoded, length $empty->encode ); is( $hex1, $hex2, 'encode/decode transparent' ); is( $hex3, $wire, 'encoded RDATA matches example' ); } { my @rdata = @data; my $sig = pop @rdata; my $lc = new Net::DNS::RR( lc(". $type @rdata ").$sig ); my $rr = new Net::DNS::RR( uc(". $type @rdata ").$sig ); my $hash = {}; my $predecessor = $rr->encode( 0, $hash ); my $compressed = $rr->encode( length $predecessor, $hash ); ok( length $compressed == length $predecessor, 'encoded RDATA not compressible' ); is( $rr->encode, $lc->encode, 'encoded RDATA names downcased' ); is( $rr->canonical, $lc->encode, 'canonical RDATA names downcased' ); } { my $rr = new Net::DNS::RR("$name $type @data"); $rr->print; } exit; Net-DNS-SEC-0.21/t/Kexample.com.+001+28551.private0000644000175100017510000000164512422405404020001 0ustar willemwillemPrivate-key-format: v1.2 Algorithm: 1 (RSA) Modulus: 0ev6AZoBi++749Ma4HxGn96UmiZa/gb8ZFPDvlanM/XaQg07bL+gSdhOrbfl2fVYKhbUI4XuICN3QGeVrv8bxqqtgXwhMT0MS8RtezbfIk5buzaUfY3PhRxY5kTzMrwhPf4pJ5O5IsHpNbbb79LTc1SmZViQwvCVAE6xV6Zvhwk= PublicExponent: Aw== PrivateExponent: i/Kmq7wBB/Un7TdnQFLZv+m4ZsQ8qVn9mDfX1DnEzU6RgV4nndUVhpA0c8/ukU46xrniwllJasJPgEUOdKoSgzwl/K15z2g+IM52K8CwaPOmVbCP0meiUfmmQuEtZBwUU6/HYWN6zL5jfUERqz+ekkvY1h3DtL3yQq8NvlOibmM= Prime1: 9f/4py2p91NRNzXzmBKakOrgOZlyBM7SgWf6KaLIBCBKqM5Mso3m05XsUiDQnCRAUnTSCyGIemBdug+NBaEUzw== Prime2: 2nSN0LzQKVvJV4ZF/cPqT/dadCNP7Y03pHeHyYxUjeJ1za/Iy/MI0L4NgyCeV0FXkGxSIMmrWUk+jg0tI1rMpw== Exponent1: o//7Gh5xT4zgz3lNEAxnC0dAJmZMAzSMVkVRcRcwAsAxxd7dzF6Z4mPy4Ws1vW2ANviMB2uwUZWT0V+zWRYN3w== Exponent2: kaMJNdM1cOfbj67ZU9fxiqTm+BeKnl4lGE+v27LjCUGj3nUwh/dbNdQJAhW+5NY6YEg2wIZyO4YptAjIwjyIbw== Coefficient: R33iGsdBa8l4YqeSWRMaud+usrKDPw5g6TwZuAoqO1GRLLkSLcGFCWV8m70up4ZD4jPMKTd5Hi6ZqXvKfSqFdw== Net-DNS-SEC-0.21/t/05-DS.t0000644000175100017510000000322012422405404013734 0ustar willemwillem# $Id: 05-DS.t 1137 2013-12-10 14:48:08Z willem $ -*-perl-*- use strict; use Test::More tests => 13; use Net::DNS; my $name = 'DS.example'; my $type = 'DS'; my $code = 43; my @attr = qw( keytag algorithm digtype digest ); my @data = ( 60485, 5, 1, '2bb183af5f22588179a53b0a98631fad1a292118' ); my @also = qw( digestbin babble ); my $wire = join '', qw( EC45 05 01 2BB183AF5F22588179A53B0A98631FAD1A292118 ); { my $typecode = unpack 'xn', new Net::DNS::RR(". $type")->encode; is( $typecode, $code, "$type RR type code = $code" ); my $hash = {}; @{$hash}{@attr} = @data; my $rr = new Net::DNS::RR( name => $name, type => $type, %$hash ); my $string = $rr->string; my $rr2 = new Net::DNS::RR($string); is( $rr2->string, $string, 'new/string transparent' ); is( $rr2->encode, $rr->encode, 'new($string) and new(%hash) equivalent' ); foreach (@attr) { is( $rr->$_, $hash->{$_}, "expected result from rr->$_()" ); } foreach (@also) { is( $rr2->$_, $rr->$_, "additional attribute rr->$_()" ); } my $empty = new Net::DNS::RR("$name $type"); my $encoded = $rr->encode; my $decoded = decode Net::DNS::RR( \$encoded ); my $hex1 = uc unpack 'H*', $decoded->encode; my $hex2 = uc unpack 'H*', $encoded; my $hex3 = uc unpack 'H*', substr( $encoded, length $empty->encode ); is( $hex1, $hex2, 'encode/decode transparent' ); is( $hex3, $wire, 'encoded RDATA matches example' ); $rr->algorithm('RSASHA512'); is( $rr->algorithm(), 10, 'algorithm mnemonic accepted' ); $rr->digtype('SHA256'); is( $rr->digtype(), 2, 'digest type mnemonic accepted' ); } { my $rr = new Net::DNS::RR("$name $type @data"); $rr->print; } exit; Net-DNS-SEC-0.21/t/54-DS-SHA384.t0000644000175100017510000000174012422405404014615 0ustar willemwillem# $Id: 54-DS-SHA384.t 1137 2013-12-10 14:48:08Z willem $ use strict; BEGIN { use Test::More; plan tests => 5; use_ok('Net::DNS::SEC'); use_ok('Digest::SHA'); } # Simple known-answer tests based upon the examples given in RFC6605, section 6.2 my $dnskey = Net::DNS::RR->new( 'example.net. 3600 IN DNSKEY 257 3 14 ( xKYaNhWdGOfJ+nPrL8/arkwf2EY3MDJ+SErKivBVSum1 w/egsXvSADtNJhyem5RCOpgQ6K8X1DRSEkrbYQ+OB+v8 /uX45NBwY8rp65F6Glur8I/mlVNgF6W/qTI37m40 )' ); my $ds = Net::DNS::RR->new( 'example.net. 3600 IN DS 10771 14 4 ( 72d7b62976ce06438e9c0bf319013cf801f09ecc84b8 d7e9495f27e305c6a9b0563a9b5f4d288405c3008a94 6df983d6 )' ); my $test = create Net::DNS::RR::DS( $dnskey, digtype => 'SHA384', ttl => 3600 ); is( $test->string, $ds->string, 'created DS matches RFC6605 example DS' ); ok( $test->verify($dnskey), 'created DS verifies RFC6605 example DNSKEY' ); ok( $ds->verify($dnskey), 'RFC6605 example DS verifies DNSKEY' ); $ds->print; __END__ Net-DNS-SEC-0.21/t/07-sec.t0000644000175100017510000001223412422405404014207 0ustar willemwillem# Test script for dnssec functionalty -*-perl-*- # $Id: 07-sec.t 1170 2014-02-10 10:42:45Z willem $ # # Called in a fashion simmilar to: # /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-freebsd \ # -I/usr/lib/perl5/5.6.1 -e 'use Test::Harness qw(&runtests $verbose); \ # $verbose=0; runtests @ARGV;' t/07-sec.t use Test::More tests=>23; use strict; use MIME::Base64; use Data::Dumper; BEGIN { use_ok('Net::DNS::SEC'); } # test 1 #diag ("Testing the algorithm method"); is (Net::DNS::SEC->algorithm("DSA"),3,"Class method parses DSA"); is (Net::DNS::SEC->algorithm("DsA"),3,"Class method parses DsA"); is (Net::DNS::SEC->algorithm("RSASHA1"),5,"Class method parses RSASHA1"); is (Net::DNS::SEC->algorithm("RSAMD5"),1,"Class method parses RSAMD5"); is ( eval{ Net::DNS::SEC->algorithm("CRYPTSAM") }, undef, "Class method detects unknown mnemonic"); my $keyrr = Net::DNS::RR->new("test.tld. IN DNSKEY 256 3 1 AQPoBLAXetIEWcEFDs+Z1Ymc2RPZeRtk/kF7bxLJOiGye5PVHDs6Vs1U 2JP7hLTglRLSK1Vu+C1iYNkYxTed9k/56vbS4lGj+a7qFKQlbcxfkRLy j8ac5JPXNIIfX5oDVjoCWF8t5sL7KxUp+0ticRyjqgc2Khg6ZgejNivl 3S0v+w=="); ok( $keyrr, "Key successfully created" ); is( $keyrr->algorithm,1,"DNSKEY with numeric specification of the RR read from string"); ok (my $keyrr2=Net::DNS::RR->new("test.tld. IN DNSKEY 256 3 RSAMD5 AQPoBLAXetIEWcEFDs+Z1Ymc2RPZeRtk/kF7bxLJOiGye5PVHDs6Vs1U 2JP7hLTglRLSK1Vu+C1iYNkYxTed9k/56vbS4lGj+a7qFKQlbcxfkRLy j8ac5JPXNIIfX5oDVjoCWF8t5sL7KxUp+0ticRyjqgc2Khg6ZgejNivl 3S0v+w=="),"Key successfully created"); is( $keyrr2->algorithm,1,"DNSKEY with string specification of the RR read from string"); is ($keyrr2->algorithm("mnemonic"),"RSAMD5","mnemonic works as argument"); # This keyblob represents t/Kexample.com.+005+34247.private; # using 'openssl rsa -modulus', 'openssl rsa -text' I double # checked if the values reported by openssl and those in the file # are consistent. my $keyblob="-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQCqyylc732/AE42mlUE3g44JS3O4tdvUwOK3lwpQ/xOJX6gFLEg /SRK36FXnXqbJzkqCkwVrCgbA2SM63axme57vbbnppljuiCKf6rxZE2602YhOLPd sw+1nRRyHZ8fPv761H8bPS9Zcx3IQyE33l1B+tPN9MtQus6fcsQy2tIwuwIBAwKB gHHcxj30/n9ViXm8OK3pXtAYyTSXOko3V7HpksYtUt7DqcANy2tTbYc/wOUTpxIa JhwG3WPIGrys7bNHpHZmnvwSTuZCYv7G6X9fG29P4HMMp4DvMlLRYcwoqcxax8DN 4XG/jBN/tfTkgUzO9sMtP6SDGsegTRER8WsYH3Ysg0L7AkEA1GAZ1v3tA96l2os1 enQEtINZ/Q2IHsd7Rr32qaTAS9qtTT5DQJKFvTA36+6+UiZ/0OxUaH2VECpuMHvh 3vz8xQJBAM3gdGwG+IvjpZZ2lPIJCYvnhdTa2Vo1iBlXyOvOvb5SIufuur0L5F8r nSDAVMhXS2U/ThvaIg+6EJ4ZH7kQT38CQQCNlWaPU/NX6cPnB3j8TVh4V5FTXlq/ L6eEfqRxGIAykcjeKYIrDFkoys/ynymMGaqLSDhFqQ4KxvQgUpaUqKiDAkEAiUBN nVn7B+0ZDvm4oVtbsppZOJHmPCOwEOUwnTR+fuFsmp8nKLKYP3JowIA4hY+HmNTe vTwWtSa1vrtqe2A0/wJAOGDWYhImmtzR/wYJyBliYPnn5fbMS/B9eL+PWC0+whBQ A5WkPqeImlJKkr7oWZE+VmuxicpW2VPVacMQYsV3dg== -----END RSA PRIVATE KEY----- "; my $privkeyfilename="t/Kexample.com.+005+34247.private"; my $pubkeyfilename="t/Kexample.com.+005+34247.key"; my $rsakey=Net::DNS::SEC::Private->new($privkeyfilename); my $privkey; my $pubkey; my $rsakeyfromder=Net::DNS::SEC::Private->new_rsa_priv($rsakey->dump_rsa_private_der); is ($rsakey->dump_rsa_private_der,$rsakeyfromder->dump_rsa_private_der, "Consistent DER parsing"); is ($rsakey->dump_rsa_private_der,$keyblob, "Consistent DER with keyblob"); #encode_base64($modulus) ."\n"; open(PRIVKEYFILE,"<$privkeyfilename" )|| die "Could not open testfile $privkeyfilename\n"; while (){ $privkey.=$_; } open(PUBKEYFILE,"<$pubkeyfilename" )|| die "Could not open testfile $pubkeyfilename\n"; while (){ $pubkey.=$_; } my $pubkeyrr=Net::DNS::RR->new($pubkey); my $dumpkey=$rsakey->dump_rsa_priv; is( $dumpkey,$privkey,"Read and dumped private keys equal"); my $key_rdata=$rsakey->dump_rsa_pub; my $key_rr_rdata=$pubkeyrr->key; is ($key_rr_rdata,$key_rdata,"Read and dumped public keys equal"); is($rsakey->dump_rsa_keytag(256),34247,"Calculated proper keytag"); # more consistency checking... Dump priv key into der format.. read it and # check again. my $der=$rsakey->dump_rsa_private_der; my $rsakey2=Net::DNS::SEC::Private->new_rsa_priv($der); my $dumpkey2=$rsakey2->dump_rsa_priv; is( $dumpkey2,$privkey,"Read and dumped private keys equal"); my $key_rdata2=$rsakey2->dump_rsa_pub; is ($key_rr_rdata,$key_rdata2,"Read and dumped public keys equal"); my $newkey=Net::DNS::SEC::Private->generate_rsa("example.com",257,1024); my $tstpubkeyrr= Net::DNS::RR->new ($newkey->signame." IN DNSKEY 257 3 5 ". $newkey->dump_rsa_pub()); is($tstpubkeyrr->keytag,$newkey->dump_rsa_keytag(),"Consistent keytag calculation"); my $sigrr= create Net::DNS::RR::RRSIG([$tstpubkeyrr],$newkey); is ($sigrr->keytag,$tstpubkeyrr->keytag,"Consisted keytag in the created signature");; ok($sigrr->verify([$tstpubkeyrr],$tstpubkeyrr), "Self verification consistent."); $privkeyfilename="t/Kexample.com.+001+28551.private"; $pubkeyfilename="t/Kexample.com.+001+28551.key"; $rsakey=Net::DNS::SEC::Private->new($privkeyfilename); $rsakeyfromder=Net::DNS::SEC::Private->new_rsa_priv($rsakey->dump_rsa_private_der); is ($rsakey->dump_rsa_private_der,$rsakeyfromder->dump_rsa_private_der, "Consistent DER parsing"); is($rsakey->dump_rsa_keytag(255,1),28551,"Consistent RSAMD5 keytag"); Net-DNS-SEC-0.21/t/11-sep.t0000644000175100017510000000176112422405404014222 0ustar willemwillem#!/usr/bin/perl -sw # Test script for dnssec functionalty # $Id: 11-sep.t 1166 2014-01-22 10:49:35Z willem $ # # Called in a fashion simmilar to: # /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-freebsd \ # -I/usr/lib/perl5/5.6.1 -e 'use Test::Harness qw(&runtests $verbose); \ # $verbose=0; runtests @ARGV;' t/10-typeroll.t use Test::More tests=>6; use strict; BEGIN {use_ok('Net::DNS'); } # test 1 ok (my $key=Net::DNS::RR->new("test.foo 3600 IN DNSKEY 256 3 RSASHA1 ( AQPDgM2XU2rluutXFw6IJjDRSGHehcc1ZtMoG5RR/ jXJD1bZNFgqsKlJkVfj9wzrzAnBg7ZQSHwxYIGDm ocdBtW3 )"),"Key created"); my $keytag=$key->keytag; $key->sep(1); ok ($key->sep, "Sep bit set"); ok ($keytag != $key->keytag, "keytag modified after toggle"); $key->sep(0); ok (!$key->sep, "Sep bit unset"); ok ($keytag == $key->keytag, "keytag modified back to original after toggle"); Net-DNS-SEC-0.21/t/05-NSEC3.t0000644000175100017510000000640312422405404014247 0ustar willemwillem# $Id: 05-NSEC3.t 1268 2014-09-29 08:09:00Z willem $ -*-perl-*- use strict; use Test::More tests => 27; use Net::DNS; my $name = '0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example'; my $type = 'NSEC3'; my $code = 50; my @attr = qw( algorithm flags iterations salt hnxtname typelist ); my @data = qw( 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS SOA NSEC3PARAM RRSIG ); my @hash = ( qw( 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr ), q(DNSKEY MX NS NSEC3PARAM RRSIG SOA) ); my @also = qw( optout ); my $wire = '0101000c04aabbccdd14174eb2409fe28bcb4887a1836f957f0a8425e27b000722010000000290'; { my $typecode = unpack 'xn', new Net::DNS::RR(". $type")->encode; is( $typecode, $code, "$type RR type code = $code" ); my $hash = {}; @{$hash}{@attr} = @hash; my $rr = new Net::DNS::RR( name => $name, type => $type, %$hash ); my $string = $rr->string; my $rr2 = new Net::DNS::RR($string); is( $rr2->string, $string, 'new/string transparent' ); is( $rr2->encode, $rr->encode, 'new($string) and new(%hash) equivalent' ); foreach (@attr) { is( $rr->$_, $hash->{$_}, "expected result from rr->$_()" ); } foreach (@also) { is( $rr2->$_, $rr->$_, "additional attribute rr->$_()" ); } my $null = new Net::DNS::RR("$name NULL")->encode; my $empty = new Net::DNS::RR("$name $type")->encode; my $rxbin = decode Net::DNS::RR( \$empty )->encode; my $txtext = new Net::DNS::RR("$name $type")->string; my $rxtext = new Net::DNS::RR($txtext)->encode; my $encoded = $rr->encode; my $decoded = decode Net::DNS::RR( \$encoded ); my $hex1 = unpack 'H*', $encoded; my $hex2 = unpack 'H*', $decoded->encode; my $hex3 = unpack 'H*', substr( $encoded, length $null ); is( $hex2, $hex1, 'encode/decode transparent' ); is( $hex3, $wire, 'encoded RDATA matches example' ); is( length($empty), length($null), 'encoded RDATA can be empty' ); is( length($rxbin), length($null), 'decoded RDATA can be empty' ); is( length($rxtext), length($null), 'string RDATA can be empty' ); } { use Net::DNS::RR::NSEC3 qw(name2hash); my $algorithm = 1; # test vectors from RFC5155 my $iteration = 12; my $salt = pack 'H*', 'aabbccdd'; my @name = qw(example a.example ai.example ns1.example ns2.example w.example *.w.example x.w.example y.w.example x.y.w.example); my %testcase = ( 'example' => '0p9mhaveqvm6t7vbl5lop2u3t2rp3tom', 'a.example' => '35mthgpgcu1qg68fab165klnsnk3dpvl', 'ai.example' => 'gjeqe526plbf1g8mklp59enfd789njgi', 'ns1.example' => '2t7b4g4vsa5smi47k61mv5bv1a22bojr', 'ns2.example' => 'q04jkcevqvmu85r014c7dkba38o0ji5r', 'w.example' => 'k8udemvp1j2f7eg6jebps17vp3n8i58h', '*.w.example' => 'r53bq7cc2uvmubfu5ocmm6pers9tk9en', 'x.w.example' => 'b4um86eghhds6nea196smvmlo4ors995', 'y.w.example' => 'ji6neoaepv8b5o6k4ev33abha8ht9fgc', 'x.y.w.example' => '2vptu5timamqttgl4luu9kg21e0aor3s', ); foreach my $name (@name) { my $hash = $testcase{$name}; my @args = ( $algorithm, $name, $iteration, $salt ); is( name2hash(@args), $hash, "H($name)" ); } } { my @rdata = qw(1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr A); my $rr = new Net::DNS::RR(". $type @rdata"); is( $rr->salt, '', 'parse RR with salt field placeholder' ); is( $rr->rdstring, "@rdata", 'placeholder denotes empty salt field' ); } exit; Net-DNS-SEC-0.21/t/09-dnssec.t0000644000175100017510000006510712422405404014725 0ustar willemwillem#!/usr/bin/perl -sw # Test script for dnssec functionalty # $Id: 09-dnssec.t 1113 2013-09-20 09:10:06Z willem $ # # Called in a fashion simmilar to: # /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-freebsd \ # -I/usr/lib/perl5/5.6.1 -e 'use Test::Harness qw(&runtests $verbose); \ # $verbose=0; runtests @ARGV;' t/09-dnssec.t use Net::DNS::RR::RRSIG; use Test::More tests=>93; use strict; BEGIN { use_ok('Net::DNS'); } my $datarrset; my ($datarr1, $datarr2, $datarr3); my $datastring1="test.tld. 7000 IN NS ns.test.tld."; my $datastring2="test.tld. 7000 IN NS ns.foo.tld."; my $datastring3="test.tld. 7000 IN NS ns.boo.tld."; my $otherrrset; my ($otherrr1, $otherrr2, $otherrr3); my $otherstring1="*.test.tld. 7000 IN TXT cruft"; my $otherstring2="*.test.tld. 7000 IN TXT more cruft."; my $otherstring3="*.test.tld. 7000 IN TXT last cruft"; $datarr1= new Net::DNS::RR($datastring1); ok ( $datarr1, 'data RR 1 loaded '); $datarr2= new Net::DNS::RR($datastring2); ok ( $datarr2, 'data RR 2 loaded '); $datarr3= new Net::DNS::RR($datastring3); ok ( $datarr3, 'data RR 3 loaded '); $datarrset = [ $datarr1, $datarr2 , $datarr3 ] ; $otherrr1= new Net::DNS::RR($otherstring1); ok ( $otherrr1, 'other RR 1 loaded '); $otherrr2= new Net::DNS::RR($otherstring2); ok ( $otherrr2, 'other RR 2 loaded '); $otherrr3= new Net::DNS::RR($otherstring3); ok ( $otherrr3, 'other RR 3 loaded '); $otherrrset = [ $otherrr1, $otherrr2 , $otherrr3 ] ; ############################################## # In the following tests we first sign a KEY and then verify it again. # We do this for both RSA and DSA. # This is a consistency check # # The private key will be written to disk first. # # Keypairs generated with dnssec-keygen. (9.2.0rc1) # # RSA/SHA-1 keypair # my $keypathrsa="Ktest.tld.+001+11567.private"; my $privrsakey= << 'ENDRSA' ; Private-key-format: v1.2 Algorithm: 1 (RSA) Modulus: 6ASwF3rSBFnBBQ7PmdWJnNkT2XkbZP5Be28SyTohsnuT1Rw7OlbNVNiT+4S04JUS0itVbvgtYmDZGMU3nfZP+er20uJRo/mu6hSkJW3MX5ES8o/GnOST1zSCH1+aA1Y6AlhfLebC+ysVKftLYnEco6oHNioYOmYHozYr5d0tL/s= PublicExponent: Aw== PrivateExponent: mq3KulHhWDvWA181ETkGaJC35lC87f7WUkoMhibBIae342gnfDneOJBip63N6w4MjBzjn1AeQZXmEIN6aU7f+q0Fwsyl4FzrSa8ehjfTS4u4YZE/Zk9rv0VIZuYwyccgLEBLYNBYRLbkbuSqDspw+Th8dCGy7XZ06eRkGZSNMjs= Prime1: 9Fssra0OAl4kNX105Xdrnb7kS+/6QgWeJeBJCuajjWQ0uRiEClDzjVVVr6BW2DixP+6RCbSDioSIqsNc546UtQ== Prime2: 8xMCAavFa+/XWHjnNJgCob976feJK2yaJrU7+2oxHiWLPtWYo+2gi2kt9Kv1aTp8lV327ddSqdO7tNJilsrP7w== Exponent1: oudzHnNerD7CzlOjQ6TyaSnth/VRgVkUGUAwse8Xs5gjJhBYBuCiXjjjymrkkCXLf/RgsSMCXFhbHII977RjIw== Exponent2: ogysAR0uR/U6OvtEzbqsa9T9RqUGHPMRbyN9UkbLaW5c1I5lwp5rB5tz+HKjm3xTDj6kno+McTfSeIxBudyKnw== Coefficient: Cxwv14w+KY7rmiO4U0giXqOij9gON7TiByj5dQjHGUQdaQEJ0zK2SlxouEfgi3hcxTGI753pFmW0cF/MDjFURw== ENDRSA open (RSA,">$keypathrsa") or die "Could not open $keypathrsa"; print RSA $privrsakey; close(RSA); my $rsakeyrr=new Net::DNS::RR ("test.tld. IN KEY 256 3 1 AQPoBLAXetIEWcEFDs+Z1Ymc2RPZeRtk/kF7bxLJOiGye5PVHDs6Vs1U 2JP7hLTglRLSK1Vu+C1iYNkYxTed9k/56vbS4lGj+a7qFKQlbcxfkRLy j8ac5JPXNIIfX5oDVjoCWF8t5sL7KxUp+0ticRyjqgc2Khg6ZgejNivl 3S0v+w== "); ok( $rsakeyrr, 'RSA/SHA-1 public key created'); # # RSA/SHA-256 keypair # my $keypathrsa256="Ktest.tld.+008+31374.private"; my $privrsakey256= << 'ENDRSA' ; Private-key-format: v1.2 Algorithm: 8 (RSASHA256) Modulus: qMM+u+1QBzYCm6PteHMyPhLBLwagdf3SfkPwWUcjdfpFHKssWWKIVHNOhaYJy/YqyTeVpG+Ij6SdSeh/QN9G/p8k4UYsvlr9G6aofgcHrVOS3xVMXK4iH6P4UTvoNBuX48wHWC9426MyODf3DcK2NxDSdnOfhpUBBvC3z3mTSrM= PublicExponent: AQAB PrivateExponent: YN0v9M2RUZI+jPbaJnh4Lgi1uTgkgZTebHqySYv7Xov3fy0Al41mkpJcT3mtxdPVWwj8axVZXJkvbmx0HdgJ9sx9SoF5HmF078O5y7yit78gbbOEKyGRlU7kfEQrQ6uHBO99LJVtr89KplW3qVKwgH2FBiAyI9dNkevebJ4R8AE= Prime1: 3GiJfuE1kaPIH6TH+b0nmH+bCQ0a7egDVrPcLVh9ybENy3KbvkRy3MYgBXBt/Zv8QgtQA+esGIwSWzxurzp1Mw== Prime2: xAO6HUsZibwUv3aX9F2oPH1YmeZpdOXIdBMN4RpibbRqs5TfKQy8281nW5dKcFG97K9jKVGv9HGgPSuBC7DUgQ== Exponent1: iZrqXMCWBTtPshHal9y0X80rKdd4vJdhnjvkdpsMzWMwzZfcDEoHvDYlv7+VrAQ61bDiX82/8ANjYnq0T8obaQ== Exponent2: htg9h/trFSrTZyfRv2VS4FImyrEM6UNOlDOrf6kj/253XRVUNCw0HE4BBaxdpElHi/TYFcvBbTthzdMI0p8SgQ== Coefficient: pXn2+3pGnSRX9fDliY1msoLu8dLzzZaYzxKl8NDCaBfj8XJEs0Ix7iovG886LLoZ2bLAZkS+1ZbRfFr+1wbmqA== ENDRSA open (RSA,">$keypathrsa256") or die "Could not open $keypathrsa256"; print RSA $privrsakey256; close(RSA); my $rsakeyrr256=new Net::DNS::RR ("test.tld. IN KEY 256 3 1 AQPoBLAXetIEWcEFDs+Z1Ymc2RPZeRtk/kF7bxLJOiGye5PVHDs6Vs1U 2JP7hLTglRLSK1Vu+C1iYNkYxTed9k/56vbS4lGj+a7qFKQlbcxfkRLy j8ac5JPXNIIfX5oDVjoCWF8t5sL7KxUp+0ticRyjqgc2Khg6ZgejNivl 3S0v+w== "); ok( $rsakeyrr256, 'RSA/SHA-256 public key created'); # # RSA/SHA-512 keypair # my $keypathrsa512="Ktest.tld.+010+04625.private"; my $privrsakey512= << 'ENDRSA' ; Private-key-format: v1.2 Algorithm: 10 (RSASHA512) Modulus: 8feFRviN7LXET8rIBgoePE1Aj4Rml4bIEe24UiqOKsf5rsYy+F3T2HEYszKhhVpXFje3cjbtLOCnKsrg2iT+QQn8PBrc9y/AZ6sdR+qdYICx4V/QoCrzaBWIE6CUB3m1ZeoMDwnadkMGpYKuMIyi+oO8qfdYhIiElTY9/ctR7gE= PublicExponent: AQAB PrivateExponent: 6wlwYNwXoJN/ubJUUemKLTEtQTtvHElEFoY/wTCtIElX87l60V7y5RAW2hqYYxy5807z1vIbuLgQKbUgbUX54ffwans1E5jcXetTAUxYmAZbJMHJNk48ssbp8Kipr58O4BC0Fdg8iiJuUu+t4qnDp6Vxy+L4I07U1sjiUd7SpQE= Prime1: +6O0SL5Wg32Gd/oQOJchH0xojeltBVVeyayadY6dM14ygTk4kwm3+6V+lRMPHyzxzEyXDY7jV62yqxLY+0NumQ== Prime2: 9ijoalqp0VafFvv7jfQFceMmszAlnwzoxekuCdwO7CfRDHG4OOB3HvR1B/Ndr2LShS5X5pIHd1uAxPFrCYcjqQ== Exponent1: x74hG+DiIUuhUljPSWxFIWfwUj0oiaRDMkhs7sV+aMjrxAFcs/Jx9TFfcguH5FIzuNxOxrdWJEG/YeX7EC9teQ== Exponent2: ea1Q7Tlxlcu2ifr2pn2Hr3rz50EWZ59O9H1Fx5PiQHOSDw+rW1oBJ+j4bHysw4QawcBdrNhkHmi5pyAao7QMOQ== Coefficient: oEwXjm4z0dVIkNS08yDSgAj9QTZLoKjDfoO/bpLLUYh9WnwPu2Jc+1eMreVfbC0RHTohxEntUuZXsPR7Du+zEQ== ENDRSA open (RSA,">$keypathrsa512") or die "Could not open $keypathrsa512"; print RSA $privrsakey512; close(RSA); my $rsakeyrr512=new Net::DNS::RR ("test.tld. IN KEY 256 3 1 AQPoBLAXetIEWcEFDs+Z1Ymc2RPZeRtk/kF7bxLJOiGye5PVHDs6Vs1U 2JP7hLTglRLSK1Vu+C1iYNkYxTed9k/56vbS4lGj+a7qFKQlbcxfkRLy j8ac5JPXNIIfX5oDVjoCWF8t5sL7KxUp+0ticRyjqgc2Khg6ZgejNivl 3S0v+w== "); ok( $rsakeyrr512, 'RSA/SHA-512 public key created'); my $keypathdsa="Ktest.tld.+003+09734.private"; my $privdsakey= << 'ENDDSA' ; Private-key-format: v1.2 Algorithm: 3 (DSA) Prime(p): 7m5wm/8KMO1fLaBB2Wbq3s0/jMudrauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/joY2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srlslykC+LQRnsbxB5YJMgmkPaPZU8GpRcc= Subprime(q): jRgd5fwOUwUmNpcD6Uzs/tMzy3U= Base(g): a0/+JhZhnci+P8/GOvnokG3NAF10o0Pf6/oz5UpcmX89KqjPvn9aRTRI9sM2AJgFBkzrQhXcx9NPvhneW0zN/baQhaUkupJ8YazNkkVKfOM6aH9h8ONVgGNRiLEBILQa07EMzce9/+JDYFbOCajJqhb9MZlTau17GDDK+r4okJ0= Private_value(x): C7O98kp8pfDdqeuvD83nf1xc4sI= Public_value(y): kFKU1HfmfRxPWwS9mA3FBHZ9LbmEizsH7vFSD7m31crIDVpxIO02bhKyFAuurKNh6naG4iTo3ak0yv6/bP8VNFIxN2QHPnnQL72ctUpvMLe+kWX7fGXuXWPIUCWVnbAeP2SnxpjxU039E9A2Rk6Dp9Eu0oXsM8hcUUnRv6ekycA= ENDDSA my $dsakeyrr=new Net::DNS::RR ("test.tld. IN KEY 256 3 3 CI0YHeX8DlMFJjaXA+lM7P7TM8t17m5wm/8KMO1fLaBB2Wbq3s0/jMud rauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/jo Y2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srls lykC+LQRnsbxB5YJMgmkPaPZU8GpRcdrT/4mFmGdyL4/z8Y6+eiQbc0A XXSjQ9/r+jPlSlyZfz0qqM++f1pFNEj2wzYAmAUGTOtCFdzH00++Gd5b TM39tpCFpSS6knxhrM2SRUp84zpof2Hw41WAY1GIsQEgtBrTsQzNx73/ 4kNgVs4JqMmqFv0xmVNq7XsYMMr6viiQnZBSlNR35n0cT1sEvZgNxQR2 fS25hIs7B+7xUg+5t9XKyA1acSDtNm4SshQLrqyjYep2huIk6N2pNMr+ v2z/FTRSMTdkBz550C+9nLVKbzC3vpFl+3xl7l1jyFAllZ2wHj9kp8aY 8VNN/RPQNkZOg6fRLtKF7DPIXFFJ0b+npMnA "); ok( $dsakeyrr, 'DSA public key created'); open (DSA,">$keypathdsa") or die "Could not open $keypathdsa"; print DSA $privdsakey; close(DSA); # Create the signature records. my $sigrsa= create Net::DNS::RR::RRSIG($datarrset,$keypathrsa, ( ttl => 360, # sigval => 100, )); ok ( $sigrsa, 'RSA signature created'); my $sigrsa256= create Net::DNS::RR::RRSIG($datarrset,$keypathrsa256, ( ttl => 360, # sigval => 100, )); ok ( $sigrsa256, 'RSA signature created'); my $sigrsa512= create Net::DNS::RR::RRSIG($datarrset,$keypathrsa512, ( ttl => 360, # sigval => 100, )); ok ( $sigrsa512, 'RSA signature created'); is ( $sigrsa->ttl, 360, "TTL from argument"); my $sigdsa= create Net::DNS::RR::RRSIG($datarrset,$keypathdsa); ok ( $sigdsa, 'DSA signature created'); is ( $sigdsa->ttl, 7000, "TTL from RRset"); # Verify the just created signatures ok ($sigrsa->verify($datarrset,$rsakeyrr),'RSA/SHA-1 sig verifies'); # Verify the just created signatures ok ($sigrsa->verify($datarrset,$rsakeyrr256),'RSA/SHA-256 sig verifies'); # Verify the just created signatures ok ($sigrsa->verify($datarrset,$rsakeyrr512),'RSA/SHA-512 sig verifies'); # Verify the just created signatures ok ($sigdsa->verify($datarrset,$dsakeyrr), 'DSA sig verifies'); # on the other hand checking against the wrong key should fail. ok (! $sigrsa->verify($datarrset,$dsakeyrr), 'RSA sig fails agains corrupt data'); ok (! $sigdsa->verify($datarrset,$rsakeyrr), 'DSA sig fails agains corrupt data'); my $othersigrsa= create Net::DNS::RR::RRSIG($otherrrset,$keypathrsa, ( ttl => 360, )); is($othersigrsa->labels,2,"Correct label count in presence of asterisk label"); # Now corrupt the key and test again.. that should fail # Corruption is very hard to notice.. we modified one letter # in the base 64 representation. my $corrupt_rsakeyrr=new Net::DNS::RR ("test.tld. IN KEY 256 3 1 AQOi+0LmBAfV+4CdCoy81y0Z9fejYXzbXrh87u2gaJZ12ItO5bGtegfA ykgUs76ElH1fGvWBpaHqh3roImc7MGkhCMh7+G2lE7aeYsUXn5wHdBFE wZBaards8JcMEcT8nHyKHNZlq9fAhQ36guqGdZuRPqxgYfwz71VJb2t9 6KX/5w=="); ok (!$sigrsa->verify($datarrset,$corrupt_rsakeyrr),'RSA fails agains corrupt key'); my $corrupt_dsakeyrr=new Net::DNS::RR ("test.tld. IN KEY 256 3 3 CI0YHeX8DlMFJjaXA+lM7P7TM8t17m5wm/8KMO1fLaBB2Wbq3s0/jMue rauMDg1G3SrOWOgX2AITudhGzT0c0FTxztM81IbmVETd/l5XXUEG0/jo Y2DNeyxD6I4Y94VcgUyf0l9ronUw+wXBhWCuueJPXSDIbbUDdcI7srls lykC+LQRnsbxB5YJMgmkPaPZU8GpRcdrT/4mFmGdyL4/z8Y6+eiQbc0A XXSjQ9/r+jPlSlyZfz0qqM++f1pFNEj2wzYAmAUGTOtCFdzH00++Gd5b TM39tpCFpSS6knxhrM2SRUp84zpof2Hw41WAY1GIsQEgtBrTsQzNx73/ 4kNgVs4JqMmqFv0xmVNq7XsYMMr6viiQnZBSlNR35n0cT1sEvZgNxQR2 fS25hIs7B+7xUg+5t9XKyA1acSDtNm4SshQLrqyjYep2huIk6N2pNMr+ v2z/FTRSMTdkBz550C+9nLVKbzC3vpFl+3xl7l1jyFAllZ2wHj9kp8aY 8VNN/RPQNkZOg6fRLtKF7DPIXFFJ0b+npMnA"); ok (! $sigdsa->verify($datarrset,$corrupt_dsakeyrr),'DSA fails agains corrupt key'); # Now test some DSA stuff my $dsrr=create Net::DNS::RR::DS($rsakeyrr); ok( $dsrr,'DS created from KEY RR'); ok( $dsrr->verify($rsakeyrr),'DS matches KEY'); my $dsrr2=Net::DNS::RR->new("test.tld. 0 IN DS 42495 1 1 0ffbeba0831b10b 8b83440dab81a2148576da 9f6"); is ($dsrr2->digest,"0ffbeba0831b10b8b83440dab81a2148576da9f6","Digest read correctly"); ok( $dsrr,'DS(2) created from string'); ok( $dsrr->verify($rsakeyrr),'DS(2) matches KEY'); my ($nlkey1, $nlsig1, $nlNS1, $nlNS2, $nlNS3, $nldatarrset); $nlNS1=new Net::DNS::RR(" host100.ws.disi. 600 IN A 10.1.1.100"); $nlNS2=new Net::DNS::RR("host100.ws.disi. 600 IN A 10.1.2.100"); $nlNS3=new Net::DNS::RR("host100.ws.disi. 600 IN A 10.1.3.100"); $nldatarrset=[$nlNS1,$nlNS3, $nlNS2]; my $dsasigrr=Net::DNS::RR::RRSIG->create($nldatarrset, $keypathdsa ); ok( $dsasigrr, 'DSA signature with bind generated key'); my $rsasigrr=Net::DNS::RR::RRSIG->create($nldatarrset, $keypathrsa ); ok( $rsasigrr, 'RSA/SHA-1 signature with bind generated key'); my $rsasigrr256=Net::DNS::RR::RRSIG->create($nldatarrset, $keypathrsa256 ); ok( $rsasigrr256, 'RSA/SHA-256 signature with bind generated key'); my $rsasigrr512=Net::DNS::RR::RRSIG->create($nldatarrset, $keypathrsa512 ); ok( $rsasigrr512, 'RSA/SHA-512 signature with bind generated key'); ok( $dsasigrr->verify($nldatarrset,$dsakeyrr),'DSA sig (test 2) verifies'); is( $dsasigrr->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); ok( $rsasigrr->verify($nldatarrset,$rsakeyrr),'RSA sig (test 2) verifies'); is( $rsasigrr->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); ######## #### Couple of SIG0 tests my $update1 = Net::DNS::Update->new("test.test"); ok ( $update1, 'Creating Update packet 1' ); $update1->push("update", Net::DNS::rr_add("test.test.test 3600 IN A 10.0.0.1")); $update1->sign_sig0($keypathrsa); ok ($rsakeyrr,'RSA Public key for SIG0'); my $update2 = Net::DNS::Update->new("test.test"); ok ( $update2, 'Creating Update packet 2' ); $update2->sign_sig0($keypathdsa); ok ($dsakeyrr,'DSA Public key for SIG0'); $update1->data; $update2->data; my $sigrr1=$update1->pop("additional"); ok ($sigrr1,"Obtained RSA sig from packet"); my $sigrr2=$update2->pop("additional"); ok ($sigrr2,"Obtained DSA sig from packet"); ok ($sigrr1->verify($update1, $rsakeyrr),'RSA SIG0 verification of packet data'); ok ($sigrr2->verify($update2, $dsakeyrr),'DSA SIG0 verification of packet data'); ok (!$sigrr1->verify($update2, $rsakeyrr),'RSA SIG0 fails with invalid data'); ok (!$sigrr2->verify($update1, $dsakeyrr),'RSA SIG0 fails with invalid data'); # # SOA with escaped dot. $datarr1 = Net::DNS::RR->new("test.tld. 7000 IN SOA ( ns.test.tld. first\.last.test.tld. 2002042603 43200 7200 1209600 7200)"); $datarrset = [ $datarr1 ] ; $sigrsa= create Net::DNS::RR::RRSIG($datarrset,$keypathrsa, ( ttl => 360, # sigval => 100, )); ok ( $sigrsa, 'RSA signature over SOA with escaped dot created'); ok ($sigrsa->verify($datarrset,$rsakeyrr),'RSA sig over SOA with escaped dot verifies'); # clean the private key files (not needed no more) # Cross check with a signature generated with bind tools. my $bindkey1=Net::DNS::RR->new(" example.com. 3600 IN DNSKEY 257 3 5 ( AQPUiszMMAi36agx/V+7Tw95l8PYmoVjHWvOKxx/0iH8ZE3sdEqQncCe Jg7IVQ+LNWSP9mT/B26eQb5WZ2IKFzNFQTMNi6um+yh3nytazwOwOx00 2VGnwpYwnUFV3bZ5BcgWC8wrUzVGgCVIvX+besZrIXMY60yriRqQqNGO DnKo2T6zYewfCw4lYxRKYT6RqA0y8nJqyLRmeZ0nYP6uvDYjHEu7mqUf XBzeZNMy3WgSCTbQoK/RaSR7adTgTe5t972c51Di7TCwxpDzCfAKuPPk liBM9Z0x4gC0AZfO5Ma0p+dhf2k7wfl8m8xEOEMJITLooy88Nh+u2c9H F1tw0naH ; key id = 40620 "); my $bindkey2=Net::DNS::RR->new(" example.com. 3600 IN DNSKEY 256 3 5 AQPaoHW/nC0fj9HuCW3hACSGiP0AkPS3dQFXDlEUjv1orbtx06TMmVKG K5K564OSd6UCf4ZQEu2CMPSAUFGHEZuANKYGwZh0k/HeoVNeom1L3Nt4 tVLiGMzrPQskzeK8sr1NKgqFmckQllMWd0ob8Ud6nqeQLHvXQgv1iHX3 dpBIPLYbRCzueqC5k09APl25PgJjjreyRXrxodvoiiaLHpdL5NtM2S9e ok2zmuRpYQSF1LTNfWwY9CkgL017Z/Zv00SbcoTM/eTXPqijGtUhh6UX 1gX89ybeyjtfcGbmTcB+I79NykZWoddO8zyzBXzzfFwtsAuryjQ/HFa5 r4mrbhkJ ; key id = 6227 "); my $bindsig=Net::DNS::RR->new(" example.com. 3600 RRSIG DNSKEY 5 2 3600 20380101000000 ( 20080225134340 40620 example.com. KXDsJ6gOFbGUA8cSwLIgnHQ2GwfpUJLWZK7/ MwF7+G2B5Ds7SQG1UWv0QuyNtWB0ubSn2ipw 4TclHDKjeYMFLD6I5Zuh4mW7n2QpPN79z57V C4Hf23lcWLRSL37jtX2qOPqWnFjy1AoGYzmy IksYcjPF5VPZyfQC0YprAQ35UKwAHfF9RMwi 7vdE0GzON1FkVCWN7uxYjnZT1jxs3EeSnR4+ 6ckK9OBJVHYUnjmIgViq6IuPV08zrelvZHcC WNFcjKKNpf3yx5YhyQBJBM6Fofl8Dk4zexsp VVjGDLrDwg73dOGEe3E00DQ9zDc++PGVNRPm r34ojumh85Ua0YVatw== ) "); my $binddataset=[$bindkey1, $bindkey2]; ok( $bindsig->verify($binddataset,$bindkey1), 'RSA sig generated with bind verifies') || diag ($bindsig->vrfyerrstr); my $nsecrr=Net::DNS::RR->new("example.com 300 NSEC itemA.with.caps.example.com. NS SOA TXT RRSIG NSEC DNSKEY "); ok ( $nsecrr, 'NSEC RR created from string'); my $nsecsig=Net::DNS::RR->new(" example.com. 300 RRSIG NSEC 5 2 300 20380101000000 ( 20080225134340 6227 example.com. TyfSavDAslOFzfiAQv29/KjGQBSyptVIHAl/ +BtV7YL7VBOBBxpYM0laQWfnvRPwqfqO0STD u3KpIH95/ZeIPA/20xqR9IqgQNx3NvMmNK2g R0qPK/tkKQpHsBGPgARXhQqUwT2HhhmwNOYb ZwvnbaarFVq3RWerJUAxWHm3OABqZ1RYr6rL JEIIwEuBs9zAmR0G03Ourg+vVzkIgOoiEcBy ketBJr7FfFsRAYJ0HWOupSw16lxoUkSrEZ/f NpSwOB7zdEuDeojcfK0JaanpWihA0hiiqq0D 7RKqrnkoTrPVN4lP7bIr4q52jEBlFVIrbIzL UGtebocRBrvlmVB3+A== ) "); my @nsecdata=($nsecrr); ok( $nsecsig->verify(\@nsecdata,$bindkey2), "RRSIG over NSEC verifies") || diag ($nsecsig->vrfyerrstr); # # RSA keypair # my $keypathrsasha1="Ktest.tld.+005+29159.private"; my $privrsakeysha1= << 'ENDRSA' ; Private-key-format: v1.2 Algorithm: 5 (RSA-SHA1) Modulus: ovtC5gQH1fuAnQqMvNctGfX3o2F82164fO7toGiWddiLTuWxrXoHwcpIFLO+hJR9Xxr1gaWh6od66CJnOzBpIQjIe/htpRO2nmLFF5+cB3QRRMGQWmq3bPCXDBHE/Jx8ihzWZavXwIUN+oLqhnWbkT6sYGH8M+9VSW9rfeil/+c= PublicExponent: Aw== PrivateExponent: bKeB7q1ajqerE1xd0zoeEU6lF5ZTPOnQU0nzwEW5o+WyNJkhHlFagTGFYyJ/Aw2o6hH5ARkWnFpR8BbvfMrwv6AeCrahtJgilCpCYxwusOOikbkGR/sXP5ObscRmEuhfzVYBV62yMc34MyspHzXHNZAL+SgRswopy6MgWdAII2s= Prime1: 0GNRLAYLvgaIZ+8o/fVST6WEhQd4bDIEHnBtIxHj9NIrHL/nIerA80sth+Pwfed2zp109U+zvcizUSfJDbHRsQ== Prime2: yDgaunUKcXw3u3JZ92Crzvflpv92BeKJdL0USBn8Sxqq/xR7BWG03M6AOkjnJwlKF/z1sJHzok3kqZMuIuf5Fw== Exponent1: iuzgyAQH1ARa7/TF/qOMNRkDA1pQSCFYFErzbLaX+IwcvdVEwUcrTNzJBUKgU++kib5N+N/NKTB3i2/bXnaLyw== Exponent2: hXq8fE4G9lLP0kw7+kByifqZGf+kA+xboyi4MBFS3Lxx/2L8rkEjPd8AJttExLDcD/35IGFNFt6YcQzJbJqmDw== Coefficient: gAeUUI6YOtdNAh3kS7pOzYfn0ZrUCV8bGpZoaXANk2RL2zUiaSSa4wudhpHwMJt+psNkkiQyf4v600uHbxro4Q== ENDRSA my $rsasha1keyrr=new Net::DNS::RR ("test.tld. IN KEY 256 3 5 AQOi+0LmBAfV+4CdCoy81y0Z9fejYXzbXrh87u2gaJZ12ItO5bGtegfB ykgUs76ElH1fGvWBpaHqh3roImc7MGkhCMh7+G2lE7aeYsUXn5wHdBFE wZBaards8JcMEcT8nHyKHNZlq9fAhQ36guqGdZuRPqxgYfwz71VJb2t9 6KX/5w=="); ok( $rsasha1keyrr, 'RSA-SHA1 public key created'); open (RSA,">$keypathrsasha1") or die "Could not open $keypathrsasha1"; print RSA $privrsakeysha1; close(RSA); my $sigrsasha1= create Net::DNS::RR::RRSIG($datarrset,$keypathrsasha1, ( ttl => 360, # sigval => 100, )); ok ( $sigrsasha1, 'RSA SHA1 signature created'); ok ($sigrsasha1->verify($datarrset,$rsasha1keyrr),'RSA SHA1 sig verifies'); ok ($sigrsasha1->verify($datarrset,[$rsasha1keyrr]),'RSA SHA1 sig verifies for 1 element keyrr array'); is($sigrsasha1->vrfyerrstr,"No Error","Correct Errorstring for keyrr array (0)"); # Corrupted versions of rsasha1keyrr my $rsasha1keyrr2=new Net::DNS::RR ("test.tld. IN KEY 256 3 5 AQOi+0LmBAfV+4CdCoy81y0Z9fejYXzbXrh87u2gaJZ12ItO5bGtegfB ykgUs76ElH1fGvWBpaHqh3roImc7MGkhCMh7+G2lE7aeYsUXn5wHdBFE wZBaards8JcMEcT8nHyKHNZlq9fAhQ36guqGdZuRPqxgYfwz71VJb2t8 6KX/5w=="); my $rsasha1keyrr3=new Net::DNS::RR ("test.tld. IN KEY 256 3 5 AQOi+0LmBAfV+4CdCoy81y0Z9fejYXzbXrh87u2gaJZ12ItO5bGtegfB ykgUs76ElH1fGvWBpaHqh3roImc7MGkhCMh7+G2lE7aeYsUXn5wHdBFE wZBaards8JcMEcT8nHyKHNZlq9fAhQ36guqGdZuRPqxgYfwz71VJb2t7 6KX/5w=="); # This keyrr has been carefully crafted to have the same keytag as # rsasha1keyrr my $rsasha1keyrr4=new Net::DNS::RR ("test.tld. IN KEY 257 3 5 AQOi+0LmBAfV+4CdCoy81y0Z9fejYXzbXrh87u2gaJZ12ItO5bGtegfB ykgUs76ElH1fGvWBpaHqh3roImc7MGkhCMh7+G2lE7aeYsUXn5wHdBFE wZBaards8JcMEcT8nHyKHNZlq9fAhQ36guqGdZuRPqxgYfwz71VJb2t8 6KX/5w=="); ok ($sigrsasha1->verify($datarrset, [$rsasha1keyrr3,$rsasha1keyrr2,$rsasha1keyrr]), 'RSA SHA1 sig verifies for 3 element keyrr array '); is($sigrsasha1->vrfyerrstr,"No Error","Correct Errorstring for keyrr array (1)"); ok (! $sigrsasha1->verify($datarrset, [$rsasha1keyrr3,$rsasha1keyrr2,$rsasha1keyrr4]), 'RSA SHA1 sig fails for 3element keyrr array with broken keys'); is($sigrsasha1->vrfyerrstr,"key 1: keytag does not match key 2: keytag does not match key 3:RSA Verification failed ","Correct Errorstring for keyrr array (2)"); ok (! $sigrsasha1->verify($datarrset, [$sigrsasha1,$rsasha1keyrr2,$rsasha1keyrr3 ]), 'RSA SHA1 sig fails for 3element keyrr array with wrong object in array'); is($sigrsasha1->vrfyerrstr,"key 1:You are trying to pass Net::DNS::RR::RRSIG data for a key key 2: keytag does not match key 3: keytag does not match ","Correct Errorstring for array with non-keyobject"); ok ( $sigrsasha1->verify($datarrset, [$sigrsasha1,$rsasha1keyrr2,$rsasha1keyrr ]), 'RSA SHA1 sig validates for 3element keyrr array with wrong object in array'); ## my $dsaprivate=Net::DNS::SEC::Private->new($keypathdsa); my $dsasigrr_p=Net::DNS::RR::RRSIG->create($nldatarrset, $dsaprivate ); ok( $dsasigrr_p, 'DSA signature with bind generated key '); my $rsaprivate=Net::DNS::SEC::Private->new($keypathrsa); my $rsasigrr_p=Net::DNS::RR::RRSIG->create($nldatarrset, $rsaprivate ); ok( $rsasigrr_p, 'RSA signature with bind generated key'); ok( $dsasigrr_p->verify($nldatarrset,$dsakeyrr),'DSA sig (test 2) verifies'); is( $dsasigrr_p->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); ok( $rsasigrr_p->verify($nldatarrset,$rsakeyrr),'RSA sig (test 2) verifies'); is( $rsasigrr_p->vrfyerrstr, "No Error", "vrfyerrstr eq No Error"); ######## #### Couple of SIG0 tests repeated with the private key object as input. my $update1_p = Net::DNS::Update->new("test.test"); ok ( $update1, 'Creating Update packet 1' ); $update1_p->push("update", Net::DNS::rr_add("test.test.test 3600 IN A 10.0.0.1")); $update1_p->sign_sig0($rsaprivate); my $update2_p = Net::DNS::Update->new("test.test"); ok ( $update2_p, 'Creating Update packet 2' ); $update2_p->sign_sig0($dsaprivate); $update1_p->data; $update2_p->data; my $sigrr1_p=$update1_p->pop("additional"); ok ($sigrr1_p,"Obtained RSA sig from packet"); my $sigrr2_p=$update2_p->pop("additional"); ok ($sigrr2_p,"Obtained DSA sig from packet"); ok ($sigrr1_p->verify($update1_p, $rsakeyrr),'RSA SIG0 verification of packet data'); ok ($sigrr2_p->verify($update2_p, $dsakeyrr),'DSA SIG0 verification of packet data'); ok (!$sigrr1_p->verify($update2_p, $rsakeyrr),'RSA SIG0 fails with invalid data'); ok (!$sigrr2_p->verify($update1_p, $dsakeyrr),'RSA SIG0 fails with invalid data'); unlink($keypathrsa); unlink($keypathdsa); unlink($keypathrsasha1); is ($dsakeyrr->keylength, 1024, "DSA (KEY) Keysize "); is ($rsakeyrr->keylength, 1024, "RSA (KEY) Keysize "); is ($bindkey1->keylength, 2048, "RSA (DNSKEY) Keysize "); foreach my $i (qw(a a.b a\.b.c a.b.c a\..\.b)) { my $name=$i.".foo.example.com."; my $wildcardrr=Net::DNS::RR->new("$name 3600 IN A 10.6.6.6"); my @wildcarddata=($wildcardrr); my $wildcardsig=Net::DNS::RR->new("$name 3600 RRSIG A 5 3 3600 20380101000000 ( 20080225134340 6227 example.com. sL22DRsra7DXdkIVmxOdJsvdAthwnqZ4i6ai SK1y4npyyeZ/nrFVlGizHwyNlRgiDZGtq7+d AC0BAKaMJsNnlJDGfWzZzh5X9so2wzR9dBDQ Gq2Ijrdmo8+uLyMF1XxY+VHe2/KOZeWQperE RgS9Lo3xeluonp4zP6qJtRQpmS27ForPre1K 8bULfPIL3nsKxqRhqZwp9Zw4b36lb1/g3D7c hmvZGkyMyHCJTUWSQgSyoTmJd6n/zm8PMjn8 B2EjrCl/7V06pb/oCAvEkA2ZfIH8WuP1iBJV 0HG5B1iuaddTU2PnZCymAFKduS0e+TvEGTrH Rt1Of5Ji8GoPEJeGTA== )"); ok( $wildcardsig->verify(\@wildcarddata,$bindkey2), "RRSIG over wildcard record *.foo.example.com verifies ($name)") || diag ($wildcardsig->vrfyerrstr); } foreach my $i (qw(a a.b a\.b.c a.b.c a\..\.b)) { my $name=$i.'.bla\.foo.example.com.'; my $wildcardrr=Net::DNS::RR->new("$name 3600 IN A 10.6.6.6"); my @wildcarddata=($wildcardrr); my $wildcardsig=Net::DNS::RR->new("$name 3600 RRSIG A 5 3 3600 20380101000000 ( 20080225134340 6227 example.com. EQHVOCh81atcWt5ecH29PBwXvIWo6XY6YTqI cFmFYez919fEfSe7jdsnIJYOXZ8CoExvIPkP g2MVYPGWZ80+CS62Q0euUr9yGGx17sbd+S6t P/TbilLZPoNzjdtW4rQKYdtTmdfzWNEyR09p gjattWO+dDlS1ucgZgnovGPuIyHI6t2Q2P0u gQoF/hlt0/r9n4Nlsk7LoeknG5ksqIQNWNep C5YYD+3B9ZZyPPcW5TaGa9v+vwVKj0YC+v0G yS4tl2n/WlZb/7PgJ56xQKMeTK7iBAv6stih YBIphzZmYwUfQpAmzGI5UwCmxARM4WMQhzi4 y+liut26SfFrdU0ecw== )"); ok( $wildcardsig->verify(\@wildcarddata,$bindkey2), "RRSIG over wildcard record *.foo.example.com verifies ($name)") || diag ($wildcardsig->vrfyerrstr); } Net-DNS-SEC-0.21/t/05-RRSIG.t0000644000175100017510000000475612422405404014333 0ustar willemwillem# $Id: 05-RRSIG.t 1271 2014-10-10 21:55:38Z willem $ -*-perl-*- use strict; use Test::More tests => 18; use Net::DNS; my $name = 'net-dns.org'; my $type = 'RRSIG'; my $code = 46; my @attr = qw( typecovered algorithm labels orgttl sigexpiration siginception keytag signame signature ); my @data = ( qw( NS 7 2 3600 20130914141655 20130815141655 60909 net-dns.org ), join '', qw( IRlCjYNZCkddjoFw6UGxAga/EvxgENl+IESuyRH9vlrys yqne0gPpclC++raP3+yRA+gDIHrMkIwsLudqod4iuoA73 Mw1NxETS6lm2eQTDNzLSY6dnJxZBqXypC3Of7bF3UmR/G NhcFIThuV/qFq+Gs+g0TJ6eyMF6ydYhjS31k= ) ); my @also = qw( sigbin ); my $wire = '0002070200000E1052346FD7520CE2D7EDED076E65742D646E73036F7267002119428D83590A475D8E8170E941B10206BF12FC6010D97E2044AEC911FDBE5AF2B32AA77B480FA5C942FBEADA3F7FB2440FA00C81EB324230B0BB9DAA87788AEA00EF7330D4DC444D2EA59B67904C33732D263A767271641A97CA90B739FEDB17752647F18D85C1484E1B95FEA16AF86B3E8344C9E9EC8C17AC9D6218D2DF59'; { my $typecode = unpack 'xn', new Net::DNS::RR(". $type")->encode; is( $typecode, $code, "$type RR type code = $code" ); my $hash = {}; @{$hash}{@attr} = @data; my $rr = new Net::DNS::RR( name => $name, type => $type, %$hash ); my $string = $rr->string; my $rr2 = new Net::DNS::RR($string); is( $rr2->string, $string, 'new/string transparent' ); is( $rr2->encode, $rr->encode, 'new($string) and new(%hash) equivalent' ); foreach (@attr) { is( $rr->$_, $hash->{$_}, "expected result from rr->$_()" ); } foreach (@also) { is( $rr2->$_, $rr->$_, "additional attribute rr->$_()" ); } my $empty = new Net::DNS::RR("$name $type"); my $encoded = $rr->encode; my $decoded = decode Net::DNS::RR( \$encoded ); my $hex1 = uc unpack 'H*', $decoded->encode; my $hex2 = uc unpack 'H*', $encoded; my $hex3 = uc unpack 'H*', substr( $encoded, length $empty->encode ); is( $hex1, $hex2, 'encode/decode transparent' ); is( $hex3, $wire, 'encoded RDATA matches example' ); } { my @rdata = @data; my $sig = pop @rdata; my $lc = new Net::DNS::RR( lc(". $type @rdata ").$sig ); my $rr = new Net::DNS::RR( uc(". $type @rdata ").$sig ); my $hash = {}; my $predecessor = $rr->encode( 0, $hash ); my $compressed = $rr->encode( length $predecessor, $hash ); ok( length $compressed == length $predecessor, 'encoded RDATA not compressible' ); is( $rr->encode, $lc->encode, 'encoded RDATA names downcased' ); is( $rr->canonical, $lc->encode, 'canonical RDATA names downcased' ); } { my $rr = new Net::DNS::RR("$name $type @data"); $rr->print; } exit; Net-DNS-SEC-0.21/t/05-DNSKEY.t0000644000175100017510000000364212422405404014433 0ustar willemwillem# $Id: 05-DNSKEY.t 1141 2013-12-16 15:10:15Z willem $ -*-perl-*- use strict; use Test::More tests => 16; use Net::DNS; my $name = 'DNSKEY.example'; my $type = 'DNSKEY'; my $code = 48; my @attr = qw( flags protocol algorithm key ); my @data = ( 256, 3, 5, join '', qw( AQPSKmynfzW4kyBv015MUG2DeIQ3 Cbl+BBZH4b/0PY1kxkmvHjcZc8no kfzj31GajIQKY+5CptLr3buXA10h WqTkF7H6RfoRqXQeogmMHfpftf6z Mv1LyBUgia7za6ZEzOJBOztyvhjL 742iU/TpPSEDhm2SNKLijfUppn1U aNvv4w== ) ); my @also = qw( keybin keylength keytag privatekeyname zone revoke sep ); my $wire = join '', qw( 010003050103D22A6CA77F35B893206FD35E4C506D8378843709B97E041647E1 BFF43D8D64C649AF1E371973C9E891FCE3DF519A8C840A63EE42A6D2EBDDBB97 035D215AA4E417B1FA45FA11A9741EA2098C1DFA5FB5FEB332FD4BC8152089AE F36BA644CCE2413B3B72BE18CBEF8DA253F4E93D2103866D9234A2E28DF529A6 7D5468DBEFE3 ); { my $typecode = unpack 'xn', new Net::DNS::RR(". $type")->encode; is( $typecode, $code, "$type RR type code = $code" ); my $hash = {}; @{$hash}{@attr} = @data; my $rr = new Net::DNS::RR( name => $name, type => $type, %$hash ); my $string = $rr->string; my $rr2 = new Net::DNS::RR($string); is( $rr2->string, $string, 'new/string transparent' ); is( $rr2->encode, $rr->encode, 'new($string) and new(%hash) equivalent' ); foreach (@attr) { is( $rr->$_, $hash->{$_}, "expected result from rr->$_()" ); } foreach (@also) { is( $rr2->$_, $rr->$_, "additional attribute rr->$_()" ); } my $empty = new Net::DNS::RR("$name NULL"); my $encoded = $rr->encode; my $decoded = decode Net::DNS::RR( \$encoded ); my $hex1 = uc unpack 'H*', $decoded->encode; my $hex2 = uc unpack 'H*', $encoded; my $hex3 = uc unpack 'H*', substr( $encoded, length $empty->encode ); is( $hex1, $hex2, 'encode/decode transparent' ); is( $hex3, $wire, 'encoded RDATA matches example' ); } { my $rr = new Net::DNS::RR("$name $type @data"); $rr->print; } exit; Net-DNS-SEC-0.21/t/00-load.t0000644000175100017510000000255212422405404014347 0ustar willemwillem#!/usr/bin/perl -sw # Test script for loading parser and zonemodules # $Id: 00-load.t 1171 2014-02-26 08:56:52Z willem $ # # Called in a fashion simmilar to: # /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-freebsd \ # -I/usr/lib/perl5/5.6.1 -e 'use Test::Harness qw(&runtests $verbose); \ # $verbose=0; runtests @ARGV;' t/ # Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' use strict; BEGIN { use Test::More tests => 2; use_ok( 'Net::DNS::SEC', qw(key_difference) ); # test 1 require_ok('Net::DNS::SEC'); # test 2 } diag("\nThese tests were run with:\n"); diag(" Net::DNS::SEC $Net::DNS::SEC::VERSION"); diag(" Net::DNS::SEC (SVN) $Net::DNS::SEC::SVNVERSION"); diag(" Net::DNS $Net::DNS::VERSION"); diag(" Net::DNS (SVN) $Net::DNS::SVNVERSION"); my @module = qw( Net::DNS::RR::DNSKEY Net::DNS::RR::DS Net::DNS::RR::DLV Net::DNS::RR::KEY Net::DNS::RR::NSEC Net::DNS::RR::NSEC3 Net::DNS::RR::NSEC3PARAM Net::DNS::RR::RRSIG Net::DNS::RR::SIG Net::DNS::SEC::Private Crypt::OpenSSL::DSA Crypt::OpenSSL::RSA Crypt::OpenSSL::Bignum Digest::SHA File::Basename Math::BigInt MIME::Base64 MIME::Base32 Time::Local ); foreach my $module (@module) { eval("require $module"); diag sprintf "\t%-30s\t%s", $module, ${module}->VERSION; } Net-DNS-SEC-0.21/t/Kexample.com.+005+34247.private0000644000175100017510000000165112422405404020001 0ustar willemwillemPrivate-key-format: v1.2 Algorithm: 5 (RSASHA1) Modulus: qsspXO99vwBONppVBN4OOCUtzuLXb1MDit5cKUP8TiV+oBSxIP0kSt+hV516myc5KgpMFawoGwNkjOt2sZnue72256aZY7ogin+q8WRNutNmITiz3bMPtZ0Uch2fHz7++tR/Gz0vWXMdyEMhN95dQfrTzfTLULrOn3LEMtrSMLs= PublicExponent: Aw== PrivateExponent: cdzGPfT+f1WJebw4rele0BjJNJc6SjdXsemSxi1S3sOpwA3La1Nthz/A5ROnEhomHAbdY8gavKzts0ekdmae/BJO5kJi/sbpf18bb0/gcwyngO8yUtFhzCipzFrHwM3hcb+ME3+19OSBTM72wy0/pIMax6BNERHxaxgfdiyDQvs= Prime1: 1GAZ1v3tA96l2os1enQEtINZ/Q2IHsd7Rr32qaTAS9qtTT5DQJKFvTA36+6+UiZ/0OxUaH2VECpuMHvh3vz8xQ== Prime2: zeB0bAb4i+OllnaU8gkJi+eF1NrZWjWIGVfI6869vlIi5+66vQvkXyudIMBUyFdLZT9OG9oiD7oQnhkfuRBPfw== Exponent1: jZVmj1PzV+nD5wd4/E1YeFeRU15avy+nhH6kcRiAMpHI3imCKwxZKMrP8p8pjBmqi0g4RakOCsb0IFKWlKiogw== Exponent2: iUBNnVn7B+0ZDvm4oVtbsppZOJHmPCOwEOUwnTR+fuFsmp8nKLKYP3JowIA4hY+HmNTevTwWtSa1vrtqe2A0/w== Coefficient: OGDWYhImmtzR/wYJyBliYPnn5fbMS/B9eL+PWC0+whBQA5WkPqeImlJKkr7oWZE+VmuxicpW2VPVacMQYsV3dg== Net-DNS-SEC-0.21/t/05-NSEC.t0000644000175100017510000000455212422405404014167 0ustar willemwillem# $Id: 05-NSEC.t 1166 2014-01-22 10:49:35Z willem $ -*-perl-*- use strict; use Test::More tests => 13; use Net::DNS; my $name = 'alpha.example.com'; my $type = 'NSEC'; my $code = 47; my @attr = qw( nxtdname typelist); my @data = qw( host.example.com A MX RRSIG NSEC TYPE1234 ); my @hash = ( qw( host.example.com ), q(A MX NSEC RRSIG TYPE1234) ); my @also = qw( ); my $wire = '04686f7374076578616d706c6503636f6d000006400100000003041b000000000000000000000000000000000000000000000000000020'; { my $typecode = unpack 'xn', new Net::DNS::RR(". $type")->encode; is( $typecode, $code, "$type RR type code = $code" ); my $hash = {}; @{$hash}{@attr} = @hash; my $rr = new Net::DNS::RR( name => $name, type => $type, %$hash ); my $string = $rr->string; my $rr2 = new Net::DNS::RR($string); is( $rr2->string, $string, 'new/string transparent' ); is( $rr2->encode, $rr->encode, 'new($string) and new(%hash) equivalent' ); foreach (@attr) { is( $rr->$_, $hash->{$_}, "expected result from rr->$_()" ); } foreach (@also) { is( $rr2->$_, $rr->$_, "additional attribute rr->$_()" ); } my $null = new Net::DNS::RR("$name NULL")->encode; my $empty = new Net::DNS::RR("$name $type")->encode; my $rxbin = decode Net::DNS::RR( \$empty )->encode; my $txtext = new Net::DNS::RR("$name $type")->string; my $rxtext = new Net::DNS::RR($txtext)->encode; my $encoded = $rr->encode; my $decoded = decode Net::DNS::RR( \$encoded ); my $hex1 = unpack 'H*', $encoded; my $hex2 = unpack 'H*', $decoded->encode; my $hex3 = unpack 'H*', substr( $encoded, length $null ); is( $hex2, $hex1, 'encode/decode transparent' ); is( $hex3, $wire, 'encoded RDATA matches example' ); is( length($empty), length($null), 'encoded RDATA can be empty' ); is( length($rxbin), length($null), 'decoded RDATA can be empty' ); is( length($rxtext), length($null), 'string RDATA can be empty' ); } { my $lc = new Net::DNS::RR( lc ". $type @data" ); my $rr = new Net::DNS::RR( uc ". $type @data" ); my $hash = {}; my $predecessor = $rr->encode( 0, $hash ); my $compressed = $rr->encode( length $predecessor, $hash ); ok( ! length $compressed < length $predecessor, 'encoded RDATA not compressible' ); isnt( $rr->encode, $lc->encode, 'encoded RDATA names not downcased' ); isnt( $rr->canonical, $lc->encode, 'canonical RDATA names not downcased' ); } exit; Net-DNS-SEC-0.21/Keyset.pm0000644000175100017510000002125312422405404014364 0ustar willemwillempackage Net::DNS::Keyset; # # $Id: Keyset.pm 1271 2014-10-10 21:55:38Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1271 $)[1]; =head1 NAME Net::DNS::Keyset - DNSSEC Keyset object class =head1 SYNOPSIS use Net::DNS::Keyset; =head1 DESCRIPTION A keyset is an "administrative" unit used for DNSSEC maintenance. The bind dnssec-signzone tool uses it to generate DS records. This class provides interfaces for creating, reading and parsing keysets. Note that this class is still being developed. Attributes and methods are subject to change. =cut use strict; use integer; use warnings; use Carp; use File::Spec::Functions; require Net::DNS::SEC; require Net::DNS::ZoneFile; use vars qw($keyset_err); my $debug = 0; sub new { my ( $class, $arg1, $arg2 ) = @_; my $ref1 = ref($arg1); return &_new_from_file unless $ref1; if ( $ref1 eq 'ARRAY' ) { return &_new_from_keys unless ref($arg2); return &_new_from_keys_sigs; } return &_new_from_packet if $ref1 eq 'Net::DNS::Packet'; croak 'Could not parse argument list'; } =head2 new (from file) $keyset = Net::DNS::Keyset->new( $filename ); $keyset = Net::DNS::Keyset->new( $filename, $directory ); Constructor method which reads the specified keyset file and returns a keyset object. The optional second argument specifies the filename base directory. Sets $Net::DNS::Keyset::keyset_err and returns undef on failure. =cut sub _new_from_file { my ( $class, $file, $path ) = @_; $file = catfile( $path, $file ) if $path && !file_name_is_absolute($file); my @rr = new Net::DNS::ZoneFile($file)->read; return $class->_new_from_keys_sigs( \@rr, \@rr ); } =head2 new (by signing keys) $keyset = Net::DNS::Keyset->new( \@keyrr, $privatekeypath ); Creates a keyset object from the keys provided through the reference to an array of Net::DNS::RR::Key objects. The method will create and self-sign the whole keyset. The private keys as generated by the BIND dnssec-keygen tool are assumed to be in the current directory or, if specified, the directory indicated by $privatekeypath. Sets $Net::DNS::Keyset::keyset_err and returns undef on failure. =cut sub _new_from_keys { my ( $class, $keylist, $keypath ) = @_; my @sigrr; foreach my $key ( grep $_->type eq 'DNSKEY', @$keylist ) { my $keyname = $key->privatekeyname; my $keyfile = $keypath ? catfile( $keypath, $keyname ) : $keyname; push @sigrr, Net::DNS::RR::RRSIG->create( $keylist, $keyfile ); } return $class->_new_from_keys_sigs( $keylist, \@sigrr ); } =head2 new (from key and sig RRsets) $keyset = Net::DNS::Keyset->new( \@keyrr, \@sigrr ); Creates a keyset object from the keys provided through the references to arrays of Net::DNS::RR::DNSKEY and Net::DNS::RR::RRSIG objects. Sets $Net::DNS::Keyset::keyset_err and returns undef on failure. =cut sub _new_from_keys_sigs { my ( $class, $key_ref, $sig_ref ) = @_; my @keyrr = grep $_->type eq 'DNSKEY', @$key_ref; my @sigrr = grep $_->type eq 'RRSIG', @$sig_ref; my $keyset = bless {keys => \@keyrr, sigs => \@sigrr}, shift; return $keyset->verify ? $keyset : undef; } =head2 new (from Packet) $res = Net::DNS::Resolver->new; $res->dnssec(1); $packet = $res->query ( "example.com", "DNSKEY", "IN" ); $keyset = Net::DNS::Keyset->new( $packet ) Creates a keyset object from a Net::DNS::Packet that contains the answer to a query for the apex key records. This is the method you should use for automatically fetching keys. Sets $Net::DNS::Keyset::keyset_err and returns undef on failure. =cut sub _new_from_packet { my ( $class, $packet ) = @_; my @rrset = $packet->answer; return $class->_new_from_keys_sigs( \@rrset, \@rrset ); } =head2 keys @keyrr = $keyset->keys; Returns an array of Net::DNS::RR::Key objects =cut sub keys { my $self = shift; return @{$self->{keys}}; } =head2 sigs @keyrr = $keyset->sigs; Returns an array of Net::DNS::RR::RRSIG objects =cut sub sigs { my $self = shift; return @{$self->{sigs}}; } =head2 extract_ds @ds = $keyset->extract_ds; Extracts DS records from the keyset. Note that the keyset will be verified during extraction: All keys will need to have a valid self-signature. =cut sub extract_ds { my $self = shift; my @ds; @ds = map Net::DNS::RR::DS->create($_), $self->keys if $self->verify; return @ds; } =head2 verify die $Net::DNS::Keyset::keyset_err unless $keyset->verify; If no arguments are given: - Verifies if all signatures present verify the keyset. - Verifies if there are DNSKEYs with the SEP flag set, there is at least one RRSIG made using that key. - Verifies that if there are no DNSKEYS with the SEP flag set there is at least one RRSIG made with one of the keys from the keyset. If an argument is given, it is should be the KEYID of one of the keys in the keyset which will be verified using the corresponding RRSIG. If verification fails the method sets $Net::DNS::Keyset::keyset_err and returns 0. If verification succeeds an array is returned with the key-tags of the keys for which signatures verified. =cut sub verify { my ( $self, $keyid ) = @_; my @keys = $self->keys; my %keys; push( @{$keys{$_->keytag}}, $_ ) foreach @keys; my @sigs = $self->sigs; $keyset_err = ''; unless (@sigs) { $keyset_err = 'No signature found'; } elsif ($keyid) { @sigs = grep $_->keytag == $keyid, @sigs; $keyset_err = "No signature made with $keyid found" unless @sigs; } elsif ( my @sepkeys = grep $_->sep, @keys ) { my %sepkey = map { ( $_->keytag => $_ ) } @sepkeys; $keyset_err = 'No signature found for key with SEP flag' unless grep $sepkey{$_->keytag}, @sigs; } my %names = map { ( $_->name => $_ ) } @keys, @sigs; my @names = CORE::keys %names; $keyset_err = "Different names in the keyset: @names" if scalar(@names) > 1; foreach my $sig (@sigs) { my $keytag = $sig->keytag; my ( $key, $collision ) = @{$keys{$keytag}}; next if $sig->verify( \@keys, ( $collision ? $keys{$keytag} : $key ) ); my $vrfyerr = $sig->vrfyerrstr; my $signame = $sig->signame; print "$vrfyerr on key $signame $keytag" if $debug; $keyset_err .= "\n" if $keyset_err; $keyset_err .= "$vrfyerr on key $signame $keytag "; } return 0 if $keyset_err; $keyset_err = 'No Error'; my @tags_verified = map $_->keytag, @sigs; return @tags_verified; } =head2 string $string = $keyset->string; Returns a string representation of the keyset. =cut sub string { my $self = shift; return join "\n", map $_->string, ( $self->keys, $self->sigs ); } =head2 print $keyset->print; # similar to print( $keyset->string ) Prints the keyset. =cut sub print { my $self = shift; $_->print foreach ( $self->keys, $self->sigs ); } =head2 writekeyset $keyset->writekeyset; $keyset->writekeyset( $path ); $keyset->writekeyset( $prefix ); $keyset->writekeyset( $prefix, $path ); Writes the keyset to a file named "keyset-." in the current working directory or directory defined by the optional $path argument. The optional $prefix argument specifies the prefix that will be prepended to the domain name to form the keyset filename. =cut sub writekeyset { my $self = shift; my ( $arg1, $arg2 ) = @_; my $path = file_name_is_absolute($arg1) ? shift : $arg2 if $arg1; my $prefix = shift || 'keyset-'; my @keysetrr = ( $self->keys, $self->sigs ); my $domainname = $keysetrr[0]->name; my $keysetname = "$prefix$domainname."; my $filename = $path ? catfile( $path, $keysetname ) : $keysetname; $filename =~ s/[.]+/\./; ## avoid antisocial consequences of $path with .. open( KEYSET, "> $filename" ) || croak "Could not open $filename for writing"; print KEYSET $_->string, "\n" foreach ( $self->keys, $self->sigs ); return 1; } 1; __END__ =head1 COPYRIGHT Copyright (c) 2002 RIPE NCC. Author Olaf M. Kolkman Portions Copyright (c) 2014 Dick Franks All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. =cut Net-DNS-SEC-0.21/RR/0000755000175100017510000000000012422405450013103 5ustar willemwillemNet-DNS-SEC-0.21/RR/DNSKEY.pm0000644000175100017510000002132312422405404014436 0ustar willemwillempackage Net::DNS::RR::DNSKEY; # # $Id: DNSKEY.pm 1271 2014-10-10 21:55:38Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1271 $)[1]; use strict; use base qw(Net::DNS::RR); =head1 NAME Net::DNS::RR::DNSKEY - DNS DNSKEY resource record =cut use integer; use warnings; use Carp; use MIME::Base64; # # source: http://www.iana.org/assignments/dns-sec-alg-numbers # { my @algbyname = ( ## Reserved => 0, # [RFC4034][RFC4398] 'RSAMD5' => 1, # [RFC3110][RFC4034] 'DH' => 2, # [RFC2539] 'DSA' => 3, # [RFC3755][RFC2536] ## Reserved => 4, # [RFC6725] 'RSASHA1' => 5, # [RFC3110][RFC4034] 'DSA-NSEC3-SHA1' => 6, # [RFC5155] 'RSASHA1-NSEC3-SHA1' => 7, # [RFC5155] 'RSASHA256' => 8, # [RFC5702] ## Reserved => 9, # [RFC6725] 'RSASHA512' => 10, # [RFC5702] ## Reserved => 11, # [RFC6725] 'ECC-GOST' => 12, # [RFC5933] 'ECDSAP256SHA256' => 13, # [RFC6605] 'ECDSAP384SHA384' => 14, # [RFC6605] 'INDIRECT' => 252, # [RFC4034] 'PRIVATEDNS' => 253, # [RFC4034] 'PRIVATEOID' => 254, # [RFC4034] ## Reserved => 255, # [RFC4034] ); my %algbyval = reverse @algbyname; my @algbynum = map { ( $_, 0 + $_ ) } keys %algbyval; # accept algorithm number my %algbyname = map { s /[^A-Za-z0-9]//g; $_ } @algbyname, @algbynum; sub algbyname { my $name = shift; my $key = uc $name; # synthetic key $key =~ s /[^A-Z0-9]//g; # strip non-alphanumerics return $algbyname{$key} || croak "unknown algorithm $name"; } sub algbyval { my $value = shift; return $algbyval{$value} || $value; } } sub decode_rdata { ## decode rdata from wire-format octet string my $self = shift; my ( $data, $offset ) = @_; my $keylength = $self->{rdlength} - 4; @{$self}{qw(flags protocol algorithm keybin)} = unpack "\@$offset n C2 a$keylength", $$data; } sub encode_rdata { ## encode rdata as wire-format octet string my $self = shift; my $keybin = $self->keybin || return ''; pack 'n C2 a*', $self->flags, $self->protocol, $self->algorithm, $keybin; } sub format_rdata { ## format rdata portion of RR string. my $self = shift; my $base64 = MIME::Base64::encode $self->keybin || return ''; my @params = map $self->$_, qw(flags protocol algorithm); chomp $base64; return join ' ', @params, "(\n$base64 ) ; Key ID =", $self->keytag; } sub parse_rdata { ## populate RR from rdata in argument list my $self = shift; $self->$_(shift) for qw(flags protocol algorithm); $self->key(@_); } sub defaults() { ## specify RR attribute default values my $self = shift; $self->algorithm(1); $self->protocol(3); } sub flags { my $self = shift; $self->{flags} = 0 + shift if scalar @_; return $self->{flags} || 0; } sub protocol { my $self = shift; $self->{protocol} = 0 + shift if scalar @_; return $self->{protocol} || 0; } sub algorithm { my ( $self, $arg ) = @_; unless ( ref($self) ) { ## class method or simple function my $argn = pop || croak 'undefined argument'; return $argn =~ /[^0-9]/ ? algbyname($argn) : algbyval($argn); } return $self->{algorithm} unless defined $arg; return algbyval( $self->{algorithm} ) if $arg =~ /MNEMONIC/i; return $self->{algorithm} = algbyname($arg); } sub key { my $self = shift; $self->keybin( MIME::Base64::decode( join "", @_ ) ) if scalar @_; return MIME::Base64::encode( $self->keybin(), "" ) if defined wantarray; } sub publickey { &key; } sub keybin { my $self = shift; return $self->{keybin} || '' unless scalar @_; delete $self->{keytag}; $self->{keybin} = shift; } sub privatekeyname { my $self = shift; my $name = lc $self->{owner}->fqdn; sprintf 'K%s+%03d+%05d.private', $name, $self->algorithm, $self->keytag; } sub keylength { my $self = shift; my $keybin = $self->keybin || return undef; local $_ = algbyval( $self->{algorithm} ); if (/^RSA/) { # Modulus length, see RFC 3110 if ( my $exp_length = unpack 'C', $keybin ) { return ( length($keybin) - $exp_length - 1 ) << 3; } else { $exp_length = unpack 'x n', $keybin; return ( length($keybin) - $exp_length - 3 ) << 3; } } elsif (/^DSA/) { # Modulus length, see RFC 2536 my $T = unpack 'C', $keybin; return ( $T << 6 ) + 512; } elsif (/^EC/) { return length($keybin) << 2; } else { return undef; } } sub keytag { my $self = shift; return 0 if ( $self->{flags} & 0xC000 ) == 0xC000; # NULL KEY # RFC4034 Appendix B.1: most significant 16 bits of least significant 24 bits return unpack 'n', substr $self->keybin(), -3 if $self->{algorithm} == 1; # RFC4034 Appendix B return $self->{keytag} = do { my @kp = @{$self}{qw(flags protocol algorithm)}; my $kb = $self->{keybin} || return 0; my $od = length($kb) & 1; my $ac = 0; $ac += $_ for unpack 'n*', pack "n C2 a* x$od", @kp, $kb; $ac += ( $ac >> 16 ); $ac & 0xFFFF; } } sub zone { my $bit = 0x0100; for ( shift->{flags} ||= 0 ) { return $_ & $bit unless scalar @_; my $set = $_ | $bit; $_ = (shift) ? $set : ( $set ^ $bit ); return $_ & $bit; } } sub revoke { my $bit = 0x0080; for ( shift->{flags} ||= 0 ) { return $_ & $bit unless scalar @_; my $set = $_ | $bit; $_ = (shift) ? $set : ( $set ^ $bit ); return $_ & $bit; } } sub sep { my $bit = 0x0001; for ( shift->{flags} ||= 0 ) { return $_ & $bit unless scalar @_; my $set = $_ | $bit; $_ = (shift) ? $set : ( $set ^ $bit ); return $_ & $bit; } } sub is_sep { ## historical my $self = shift; return $self->sep(@_) ? 1 : 0; } sub set_sep { shift->is_sep(1); } ## historical sub unset_sep { shift->is_sep(0); } ## historical sub clear_sep { shift->is_sep(0); } ## historical 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name DNSKEY flags protocol algorithm publickey'); =head1 DESCRIPTION Class for DNSSEC Key (DNSKEY) resource records. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head2 flags $flags = $rr->flags; $rr->flags( $flags ); Unsigned 16-bit number representing Boolean flags. =head2 protocol $protocol = $rr->protocol; $rr->protocol( $protocol ); The 8-bit protocol number. This field MUST have value 3. =head2 algorithm $algorithm = $rr->algorithm; $rr->algorithm( $algorithm ); The 8-bit algorithm number describes the public key algorithm. algorithm() may also be invoked as a class method or simple function to perform mnemonic and numeric code translation. =head2 key $key = $rr->key; $rr->key( $key ); The key field holds the public key material. The format depends on the algorithm of the key being stored. =head2 privatekeyname $privatekeyname=$rr->privatekeyname Returns the name of the privatekey as it would be generated by the BIND dnssec-keygen program. The format of that name being: K++.private =head2 keylength Returns the length (in bits) of the modulus calculated from the key text. =head2 keytag print "keytag = ", $rr->keytag, "\n"; Returns the 16-bit numerical key tag of the key. (RFC2535 4.1.6) =head2 zone $rr->zone(0); $rr->zone(1); if ( $rr->zone ) { ... } Boolean Zone key flag. =head2 revoke $rr->revoke(0); $rr->revoke(1); if ( $rr->revoke ) { ... } Boolean Revoke flag. =head2 sep $rr->sep(0); $rr->sep(1); if ( $rr->sep ) { ... } Boolean Secure Entry Point flag. =head1 COPYRIGHT Copyright (c)2003-2005 RIPE NCC. Author Olaf M. Kolkman All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, RFC4034, RFC3755 L =cut Net-DNS-SEC-0.21/RR/DS.pm0000644000175100017510000002404612422405404013754 0ustar willemwillempackage Net::DNS::RR::DS; # # $Id: DS.pm 1276 2014-10-19 06:02:40Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1276 $)[1]; use strict; use base qw(Net::DNS::RR); =head1 NAME Net::DNS::RR::DS - DNS DS resource record =cut use integer; use warnings; use Carp; use constant BABBLE => eval { require Digest::BubbleBabble; }; eval { require Digest::SHA }; ## optional for simple Net::DNS RR eval { require Digest::GOST }; eval { require Digest::GOST::CryptoPro }; my %digest = ( '1' => ['Digest::SHA', 1], '2' => ['Digest::SHA', 256], '3' => ['Digest::GOST::CryptoPro'], '4' => ['Digest::SHA', 384], ); # # source: http://www.iana.org/assignments/dns-sec-alg-numbers # { my @algbyname = ( ## Reserved => 0, # [RFC4034][RFC4398] 'RSAMD5' => 1, # [RFC3110][RFC4034] 'DH' => 2, # [RFC2539] 'DSA' => 3, # [RFC3755][RFC2536] ## Reserved => 4, # [RFC6725] 'RSASHA1' => 5, # [RFC3110][RFC4034] 'DSA-NSEC3-SHA1' => 6, # [RFC5155] 'RSASHA1-NSEC3-SHA1' => 7, # [RFC5155] 'RSASHA256' => 8, # [RFC5702] ## Reserved => 9, # [RFC6725] 'RSASHA512' => 10, # [RFC5702] ## Reserved => 11, # [RFC6725] 'ECC-GOST' => 12, # [RFC5933] 'ECDSAP256SHA256' => 13, # [RFC6605] 'ECDSAP384SHA384' => 14, # [RFC6605] 'INDIRECT' => 252, # [RFC4034] 'PRIVATEDNS' => 253, # [RFC4034] 'PRIVATEOID' => 254, # [RFC4034] ## Reserved => 255, # [RFC4034] ); my %algbyval = reverse @algbyname; my @algbynum = map { ( $_, 0 + $_ ) } keys %algbyval; # accept algorithm number my %algbyname = map { s /[^A-Za-z0-9]//g; $_ } @algbyname, @algbynum; sub algbyname { my $name = shift; my $key = uc $name; # synthetic key $key =~ s /[^A-Z0-9]//g; # strip non-alphanumerics return $algbyname{$key} || croak "unknown algorithm $name"; } sub algbyval { my $value = shift; return $algbyval{$value} || $value; } } # # source: http://www.iana.org/assignments/ds-rr-types # { my @digestbyname = ( 'SHA-1' => 1, # RFC3658 'SHA-256' => 2, # RFC4509 'GOST' => 3, # RFC5933 'SHA-384' => 4, # RFC6605 ); my @digestbyalias = ( 'SHA' => 1 ); my %digestbyval = reverse @digestbyname; my @digestbynum = map { ( $_, 0 + $_ ) } keys %digestbyval; # accept algorithm number my %digestbyname = map { s /[^A-Za-z0-9]//g; $_ } @digestbyalias, @digestbyname, @digestbynum; sub digestbyname { my $name = shift; my $key = uc $name; # synthetic key $key =~ s /[^A-Z0-9]//g; # strip non-alphanumerics return $digestbyname{$key} || croak "unknown digest type $name"; } sub digestbyval { my $value = shift; return $digestbyval{$value} || $value; } } sub decode_rdata { ## decode rdata from wire-format octet string my $self = shift; my ( $data, $offset ) = @_; my $length = $self->{rdlength} - 4; @{$self}{qw(keytag algorithm digtype digestbin)} = unpack "\@$offset n C2 a$length", $$data; } sub encode_rdata { ## encode rdata as wire-format octet string my $self = shift; return '' unless $self->{digtype}; pack 'n C2 a*', @{$self}{qw(keytag algorithm digtype digestbin)}; } sub format_rdata { ## format rdata portion of RR string. my $self = shift; return '' unless $self->{digtype}; my @babble = BABBLE ? ( "\n;", $self->babble ) : (); my $digest = $self->digest; $digest = join( "\n", '(', split /(\S{64})/, $digest ) . ' )' if length $digest > 40; join ' ', @{$self}{qw(keytag algorithm digtype)}, $digest, @babble; } sub parse_rdata { ## populate RR from rdata in argument list my $self = shift; $self->$_(shift) for qw(keytag algorithm digtype); $self->digest(@_); } sub keytag { my $self = shift; $self->{keytag} = 0 + shift if scalar @_; return $self->{keytag} || 0; } sub algorithm { my ( $self, $arg ) = @_; unless ( ref($self) ) { ## class method or simple function my $argn = pop || croak 'undefined argument'; return $argn =~ /[^0-9]/ ? algbyname($argn) : algbyval($argn); } return $self->{algorithm} unless defined $arg; return algbyval( $self->{algorithm} ) if $arg =~ /MNEMONIC/i; return $self->{algorithm} = algbyname($arg); } sub digtype { my ( $self, $arg ) = @_; unless ( ref($self) ) { ## class method or simple function my $argn = pop || croak 'undefined argument'; return $argn =~ /[^0-9]/ ? digestbyname($argn) : digestbyval($argn); } return $self->{digtype} unless defined $arg; return digestbyval( $self->{digtype} ) if $arg =~ /MNEMONIC/i; return $self->{digtype} = digestbyname($arg); } sub digest { my $self = shift; $self->digestbin( pack "H*", map { die "!hex!" if m/[^0-9A-Fa-f]/; $_ } join "", @_ ) if scalar @_; unpack "H*", $self->digestbin() if defined wantarray; } sub digestbin { my $self = shift; $self->{digestbin} = shift if scalar @_; $self->{digestbin} || ""; } sub babble { return Digest::BubbleBabble::bubblebabble( Digest => shift->digestbin ) if BABBLE; return ''; } sub create { my $class = shift; my $keyrr = shift; my %args = @_; my ($type) = reverse split '::', $class; my $kname = $keyrr->name; my $flags = $keyrr->flags; croak "Unable to create $kname $type record for non-DNSSEC key" unless $keyrr->protocol == 3; croak "Unable to create $kname $type record for NULL key" if ( $flags & 0xc000 ) == 0xc000; croak "Unable to create $kname $type record for key with flag bit7 clear" unless $flags & 0x0100; croak "Unable to create $kname $type record for key with flag bit6 set" if $flags & 0x0200; croak "Unable to create $kname $type record for key with flag bit0 set" if $flags & 0x8000; my $self = new Net::DNS::RR( name => $kname, # per definition, same as keyrr type => $type, class => $keyrr->class, ttl => $keyrr->ttl, keytag => $keyrr->keytag, algorithm => $keyrr->algorithm, digtype => 1, # SHA1 by default %args ); my $owner = $self->{owner}->encode(); my $data = pack 'a* a*', $owner, $keyrr->encode_rdata; my $arglist = $digest{$self->digtype} || croak 'unsupported digest type'; my ( $object, @argument ) = @$arglist; my $hash = $object->new(@argument); $hash->add($data); $self->digestbin( $hash->digest ); return $self; } sub verify { my ( $self, $key ) = @_; my $verify = create Net::DNS::RR::DS( $key, ( digtype => $self->digtype ) ); return $verify->digestbin eq $self->digestbin; } 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name DS keytag algorithm digtype digest'); =head1 DESCRIPTION Class for DNS Delegation Signer (DS) resource record. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head2 keytag $keytag = $rr->keytag; $rr->keytag( $keytag ); The 16-bit numerical key tag of the key. (RFC2535 4.1.6) =head2 algorithm $algorithm = $rr->algorithm; $rr->algorithm( $algorithm ); Decimal representation of the 8-bit algorithm field. algorithm() may also be invoked as a class method or simple function to perform mnemonic and numeric code translation. =head2 digtype $digtype = $rr->digtype; $rr->digtype( $digtype ); Decimal representation of the 8-bit digest type field. digtype() may also be invoked as a class method or simple function to perform mnemonic and numeric code translation. =head2 digest $digest = $rr->digest; $rr->digest( $digest ); Hexadecimal representation of the digest over the label and key. =head2 digestbin $digestbin = $rr->digestbin; $rr->digestbin( $digestbin ); Binary representation of the digest over the label and key. =head2 babble print $rr->babble; The babble() method returns the 'BubbleBabble' representation of the The babble() method returns the 'BubbleBabble' representation of the digest if the Digest::BubbleBabble package is available, otherwise an empty string is returned. BubbleBabble represents a message digest as a string of plausible words, to make the digest easier to verify. The "words" are not necessarily real words, but they look more like words than a string of hex characters. The 'BubbleBabble' string is appended as a comment to the RDATA when the string method is called. =head2 create use Net::DNS::SEC; $dsrr = create Net::DNS::RR::DS($keyrr, digtype => 'SHA-256' ); $keyrr->print; $dsrr->print; This constructor takes a key object as argument and will return the corresponding DS RR object. The digest type defaults to SHA-1. =head2 verify $verify = $dsrr->verify($keyrr); The boolean verify method will return true if the hash over the key RR provided as the argument conforms to the data in the DS itself i.e. the DS points to the DNSKEY from the argument. =head1 COPYRIGHT Copyright (c)2001-2005 RIPE NCC. Author Olaf M. Kolkman Portions Copyright (c)2013 Dick Franks. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, RFC4034, RFC3658 L, L =cut Net-DNS-SEC-0.21/RR/NSEC.pm0000644000175100017510000001164112422405404014173 0ustar willemwillempackage Net::DNS::RR::NSEC; # # $Id: NSEC.pm 1276 2014-10-19 06:02:40Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1276 $)[1]; use strict; use base qw(Net::DNS::RR); =head1 NAME Net::DNS::RR::NSEC - DNS NSEC resource record =cut use integer; use warnings; use Net::DNS::DomainName; use Net::DNS::Parameters; sub decode_rdata { ## decode rdata from wire-format octet string my $self = shift; my ( $data, $offset ) = @_; my $limit = $offset + $self->{rdlength}; ( $self->{nxtdname}, $offset ) = decode Net::DNS::DomainName(@_); $self->{typebm} = substr $$data, $offset, $limit - $offset; } sub encode_rdata { ## encode rdata as wire-format octet string my $self = shift; return '' unless $self->{typebm}; join '', $self->{nxtdname}->encode(), $self->{typebm}; } sub format_rdata { ## format rdata portion of RR string. my $self = shift; return '' unless $self->{typebm}; join ' ', $self->{nxtdname}->string(), $self->typelist; } sub parse_rdata { ## populate RR from rdata in argument list my $self = shift; $self->nxtdname(shift); $self->typelist(@_); } sub nxtdname { my $self = shift; $self->{nxtdname} = new Net::DNS::DomainName(shift) if scalar @_; $self->{nxtdname}->name if defined wantarray; } sub typelist { my $self = shift; $self->{typebm} = &_type2bm if scalar @_; my @type = defined wantarray ? &_bm2type( $self->{typebm} ) : (); return "@type" unless wantarray; return @type; } ######################################## sub _type2bm { my @typearray; foreach my $typename ( map split( /\s+/, $_ ), @_ ) { next unless $typename; my $typenum = typebyname( uc $typename ); my $window = $typenum >> 8; next unless $window or $typenum < 128; # skip meta type next if $typenum == 41; # skip meta type my $bitnum = $typenum & 255; my $octet = $bitnum >> 3; my $bit = $bitnum & 7; $typearray[$window][$octet] |= 0x80 >> $bit; } my $bitmap; my $window = 0; foreach (@typearray) { if ( my $pane = $typearray[$window] ) { my @content = map $_ || 0, @$pane; $bitmap .= pack 'CC C*', $window, scalar(@content), @content; } $window++; } return $bitmap || ''; } sub _bm2type { my $bitmap = shift || ''; my $index = 0; my $limit = length $bitmap; my @typelist; while ( $index < $limit ) { my ( $block, $size ) = unpack "\@$index C2", $bitmap; my @octet = unpack "\@$index xxC$size", $bitmap; $index += $size + 2; my $typenum = $block << 8; foreach my $octet (@octet) { $typenum += 8; my $i = $typenum; while ($octet) { --$i; push @typelist, typebyval($i) if $octet & 1; $octet = $octet >> 1; } } } return sort @typelist; } sub typebm { ## historical my $self = shift; return $self->{typebm} unless scalar @_; $self->{typebm} = shift; } sub _typearray2typebm { ## historical &_type2bm; } sub _typebm2typearray { ## historical &_bm2type; } 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name NSEC nxtdname typelist'); =head1 DESCRIPTION Class for DNSSEC NSEC resource records. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head2 nxtdname $nxtdname = $rr->nxtdname; $rr->nxtdname( $nxtdname ); The Next Domain field contains the next owner name (in the canonical ordering of the zone) that has authoritative data or contains a delegation point NS RRset. =head2 typelist @typelist = $rr->typelist; $typelist = $rr->typelist; The Type List identifies the RRset types that exist at the NSEC RR owner name. When called in scalar context, the list is interpolated into a string. =head1 COPYRIGHT Copyright (c)2001-2005 RIPE NCC. Author Olaf M. Kolkman All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, RFC4034, RFC3755 =cut Net-DNS-SEC-0.21/RR/NSEC3PARAM.pm0000644000175100017510000001143012422405404015033 0ustar willemwillempackage Net::DNS::RR::NSEC3PARAM; # # $Id: NSEC3PARAM.pm 1271 2014-10-10 21:55:38Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1271 $)[1]; use strict; use base qw(Net::DNS::RR); =head1 NAME Net::DNS::RR::NSEC3PARAM - DNS NSEC3PARAM resource record =cut use integer; use warnings; sub decode_rdata { ## decode rdata from wire-format octet string my $self = shift; my ( $data, $offset ) = @_; my $size = unpack "\@$offset x4 C", $$data; @{$self}{qw(algorithm flags iterations saltbin)} = unpack "\@$offset CCnx a$size", $$data; } sub encode_rdata { ## encode rdata as wire-format octet string my $self = shift; return '' unless $self->{algorithm}; my $salt = $self->{saltbin}; pack 'CCnCa*', @{$self}{qw(algorithm flags iterations)}, length($salt), $salt; } sub format_rdata { ## format rdata portion of RR string. my $self = shift; return '' unless $self->{algorithm}; join ' ', $self->algorithm, $self->flags, $self->iterations, $self->salt || '-'; } sub parse_rdata { ## populate RR from rdata in argument list my $self = shift; $self->algorithm(shift); $self->flags(shift); $self->iterations(shift); my $salt = shift; $self->salt($salt) unless $salt eq '-'; } sub algorithm { my $self = shift; $self->{algorithm} = 0 + shift if scalar @_; return $self->{algorithm} || 0; } sub flags { my $self = shift; $self->{flags} = 0 + shift if scalar @_; return $self->{flags} || 0; } sub iterations { my $self = shift; $self->{iterations} = 0 + shift if scalar @_; return $self->{iterations} || 0; } sub salt { my $self = shift; $self->saltbin( pack "H*", map { die "!hex!" if m/[^0-9A-Fa-f]/; $_ } join "", @_ ) if scalar @_; unpack "H*", $self->saltbin() if defined wantarray; } sub saltbin { my $self = shift; $self->{saltbin} = shift if scalar @_; $self->{saltbin} || ""; } ######################################## sub hashalgo {&algorithm} ## historical 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name NSEC3PARAM algorithm flags iterations salt'); =head1 DESCRIPTION Class for DNSSEC NSEC3PARAM resource records. The NSEC3PARAM RR contains the NSEC3 parameters (hash algorithm, flags, iterations and salt) needed to calculate hashed ownernames. The presence of an NSEC3PARAM RR at a zone apex indicates that the specified parameters may be used by authoritative servers to choose an appropriate set of NSEC3 records for negative responses. The NSEC3PARAM RR is not used by validators or resolvers. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head2 algorithm $algorithm = $rr->algorithm; $rr->algorithm( $algorithm ); The Hash Algorithm field is represented as an unsigned decimal integer. The value has a maximum of 255. =head2 flags $flags = $rr->flags; $rr->flags( $flags ); The Flags field is represented as an unsigned decimal integer. The value has a maximum of 255. =head2 iterations $iterations = $rr->iterations; $rr->iterations( $iterations ); The Iterations field is represented as an unsigned decimal integer. The value is between 0 and 65535, inclusive. =head2 salt $salt = $rr->salt; $rr->salt( $salt ); The Salt field is represented as a contiguous sequence of hexadecimal digits. A "-" (unquoted) is used in string format to indicate that the salt field is absent. =head2 saltbin $saltbin = $rr->saltbin; $rr->saltbin( $saltbin ); The Salt field as a sequence of octets. =head1 COPYRIGHT Copyright (c)2007,2008 NLnet Labs. Author Olaf M. Kolkman All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, RFC5155 =cut Net-DNS-SEC-0.21/RR/KEY.pm0000644000175100017510000000241612422405404014073 0ustar willemwillempackage Net::DNS::RR::KEY; # # $Id: KEY.pm 1276 2014-10-19 06:02:40Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1276 $)[1]; use warnings; use strict; use base qw(Net::DNS::RR::DNSKEY); =head1 NAME Net::DNS::RR::KEY - DNS KEY resource record =cut 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name KEY flags protocol algorithm publickey'); =head1 DESCRIPTION DNS KEY resource record This is a clone of the DNSKEY record and inherits all properties of the Net::DNS::RR::DNSKEY class. Please see the L documentation for details. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head1 COPYRIGHT Copyright (c)2005 Olaf Kolkman (NLnet Labs) All rights reserved. This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, L, RFC3755, RFC2535 =cut Net-DNS-SEC-0.21/RR/CDS.pm0000644000175100017510000000235212422405404014053 0ustar willemwillempackage Net::DNS::RR::CDS; # # $Id: CDS.pm 1261 2014-09-11 10:14:45Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1261 $)[1]; use warnings; use strict; use base qw(Net::DNS::RR::DS); =head1 NAME Net::DNS::RR::CDS - DNS CDS resource record =cut 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name CDS keytag algorithm digtype digest'); =head1 DESCRIPTION DNS Child DS resource record This is a clone of the DS record and inherits all properties of the Net::DNS::RR::DS class. Please see the L perl documentation for details. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head1 COPYRIGHT Copyright (c)2014 Dick Franks All rights reserved. This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, L, RFC7344 =cut Net-DNS-SEC-0.21/RR/DLV.pm0000644000175100017510000000235612422405404014073 0ustar willemwillempackage Net::DNS::RR::DLV; # # $Id: DLV.pm 1276 2014-10-19 06:02:40Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1276 $)[1]; use warnings; use strict; use base qw(Net::DNS::RR::DS); =head1 NAME Net::DNS::RR::DLV - DNS DLV resource record =cut 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name DLV keytag algorithm digtype digest'); =head1 DESCRIPTION DNS DLV resource record This is a clone of the DS record and inherits all properties of the Net::DNS::RR::DS class. Please see the L documentation for details. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head1 COPYRIGHT Copyright (c)2005 Olaf Kolkman (NLnet Labs) All rights reserved. This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, L, RFC4431 =cut Net-DNS-SEC-0.21/RR/CDNSKEY.pm0000644000175100017510000000243112422405404014540 0ustar willemwillempackage Net::DNS::RR::CDNSKEY; # # $Id: CDNSKEY.pm 1261 2014-09-11 10:14:45Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1261 $)[1]; use warnings; use strict; use base qw(Net::DNS::RR::DNSKEY); =head1 NAME Net::DNS::RR::CDNSKEY - DNS CDNSKEY resource record =cut 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name CDNSKEY flags protocol algorithm publickey'); =head1 DESCRIPTION DNS Child DNSKEY resource record This is a clone of the DNSKEY record and inherits all properties of the Net::DNS::RR::DNSKEY class. Please see the L perl documentation for details. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head1 COPYRIGHT Copyright (c)2014 Dick Franks All rights reserved. This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, L, RFC7344 =cut Net-DNS-SEC-0.21/RR/SIG.pm0000644000175100017510000006013512422405404014067 0ustar willemwillem # pre-5.14.0 perl inadvertently destroys signal handlers # http://rt.perl.org/rt3/Public/Bug/Display.html?id=76138 # BEGIN { ## capture %SIG before compilation @::SIG_BACKUP = %SIG if eval { $] < 5.014 }; } sub UNITCHECK { ## restore %SIG after compilation %SIG = @::SIG_BACKUP if eval { $] < 5.014 }; } package Net::DNS::RR::SIG; # # $Id: SIG.pm 1276 2014-10-19 06:02:40Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1276 $)[1]; use strict; use base qw(Net::DNS::RR); =head1 NAME Net::DNS::RR::SIG - DNS SIG resource record =cut use integer; use warnings; use Carp; use MIME::Base64; use Time::Local; use Net::DNS::Parameters; eval { require Crypt::OpenSSL::RSA }; ## optional for simple Net::DNS RR eval { require Crypt::OpenSSL::DSA }; eval { require Crypt::OpenSSL::Bignum }; eval { require Digest::SHA }; eval { require Net::DNS::SEC::Private }; my $debug = 0; sub decode_rdata { ## decode rdata from wire-format octet string my $self = shift; my ( $data, $offset, @opaque ) = @_; my $limit = $offset + $self->{rdlength}; my @field = qw(typecovered algorithm labels orgttl sigexpiration siginception keytag); @{$self}{@field} = unpack "\@$offset n C2 N3 n", $$data; ( $self->{signame}, $offset ) = decode Net::DNS::DomainName2535( $data, $offset + 18 ); $self->{sigbin} = substr $$data, $offset, $limit - $offset; } sub encode_rdata { ## encode rdata as wire-format octet string my $self = shift; my ( $offset, @opaque ) = @_; my ( $hash, $packet ) = @opaque; my $signame = $self->{signame} || return ''; unless ( $self->{sigbin} ) { die 'missing packet reference' unless $packet; my $sigdata = $self->_CreateSigData($packet); $self->_CreateSig( $sigdata, $self->{private} || die 'missing key reference' ); undef $self->{private}; # one shot is all you get } my @field = qw(typecovered algorithm labels orgttl sigexpiration siginception keytag); pack 'n C2 N3 n a* a*', @{$self}{@field}, $signame->encode, $self->sigbin; } sub format_rdata { ## format rdata portion of RR string. my $self = shift; my $base64 = encode_base64 $self->sigbin || return ''; my $line1 = join ' ', map $self->$_, qw(typecovered algorithm labels orgttl); my $line2 = join ' ', map $self->$_, qw(sigexpiration siginception keytag); my $signame = $self->{signame}->string; chomp $base64; return "$line1 (\n$line2 $signame\n$base64 )"; } sub parse_rdata { ## populate RR from rdata in argument list my $self = shift; my @attribute = qw(typecovered algorithm labels orgttl sigexpiration siginception keytag signame); $self->$_( scalar @_ ? shift : () ) for @attribute; $self->signature(@_); } sub defaults() { ## specify RR attribute default values my $self = shift; $self->class('ANY'); $self->parse_rdata( 'TYPE0', 1, 0, 0 ); } my %RSA = ( '1' => 'use_md5_hash', '5' => 'use_sha1_hash' ); my %DSA = ( '3' => ['Digest::SHA'] ); # # source: http://www.iana.org/assignments/dns-sec-alg-numbers # { my @algbyname = ( ## Reserved => 0, # [RFC4034][RFC4398] 'RSAMD5' => 1, # [RFC3110][RFC4034] 'DH' => 2, # [RFC2539] 'DSA' => 3, # [RFC3755][RFC2536] ## Reserved => 4, # [RFC6725] 'RSASHA1' => 5, # [RFC3110][RFC4034] 'DSA-NSEC3-SHA1' => 6, # [RFC5155] 'RSASHA1-NSEC3-SHA1' => 7, # [RFC5155] 'RSASHA256' => 8, # [RFC5702] ## Reserved => 9, # [RFC6725] 'RSASHA512' => 10, # [RFC5702] ## Reserved => 11, # [RFC6725] 'ECC-GOST' => 12, # [RFC5933] 'ECDSAP256SHA256' => 13, # [RFC6605] 'ECDSAP384SHA384' => 14, # [RFC6605] 'INDIRECT' => 252, # [RFC4034] 'PRIVATEDNS' => 253, # [RFC4034] 'PRIVATEOID' => 254, # [RFC4034] ## Reserved => 255, # [RFC4034] ); my %algbyval = reverse @algbyname; my @algbynum = map { ( $_, 0 + $_ ) } keys %algbyval; # accept algorithm number my %algbyname = map { s /[^A-Za-z0-9]//g; $_ } @algbyname, @algbynum; sub algbyname { my $name = shift; my $key = uc $name; # synthetic key $key =~ s /[^A-Z0-9]//g; # strip non-alphanumerics return $algbyname{$key} || croak "unknown algorithm $name"; } sub algbyval { my $value = shift; return $algbyval{$value} || $value; } } sub typecovered { my $self = shift; $self->{typecovered} = typebyname(shift) if scalar @_; return typebyval( $self->{typecovered} ); } sub algorithm { my ( $self, $arg ) = @_; unless ( ref($self) ) { ## class method or simple function my $argn = pop || croak 'undefined argument'; return $argn =~ /[^0-9]/ ? algbyname($argn) : algbyval($argn); } return $self->{algorithm} unless defined $arg; return algbyval( $self->{algorithm} ) if $arg =~ /MNEMONIC/i; return $self->{algorithm} = algbyname($arg); } sub labels { my $self = shift; $self->{labels} = 0 + shift if scalar @_; return $self->{labels} || 0; } sub orgttl { my $self = shift; $self->{orgttl} = 0 + shift if scalar @_; return $self->{orgttl} || 0; } sub sigexpiration { my $self = shift; $self->{sigexpiration} = _string2time(shift) if scalar @_; _time2string( $self->{sigexpiration} ) if defined wantarray; } sub siginception { my $self = shift; $self->{siginception} = _string2time(shift) if scalar @_; _time2string( $self->{siginception} ) if defined wantarray; } sub keytag { my $self = shift; $self->{keytag} = 0 + shift if scalar @_; return $self->{keytag} || 0; } sub signame { my $self = shift; $self->{signame} = new Net::DNS::DomainName2535(shift) if scalar @_; $self->{signame}->name if defined wantarray; } sub signature { my $self = shift; return encode_base64( $self->sigbin, '' ) unless scalar @_; return $self->sigbin( decode_base64( join '', @_ ) ); } sub sig { &signature; } sub sigbin { my $self = shift; $self->{sigbin} = shift if scalar @_; $self->{sigbin} || ""; } sub create { my ( $class, $data, $priv_key, %args ) = @_; my $private = ref($priv_key) ? $priv_key : Net::DNS::SEC::Private->new($priv_key); croak 'Unable to parse private key' unless ref($private) eq 'Net::DNS::SEC::Private'; my $self = new Net::DNS::RR( type => 'SIG', typecovered => 'TYPE0', siginception => $args{sigin} || time(), sigexpiration => $args{sigex} || 0, algorithm => $private->algorithm, keytag => $private->keytag, signame => $private->signame, ); $args{sigval} ||= 10 unless $self->{sigexpiration}; if ( $args{sigval} ) { my $sigin = $self->{siginception}; my $sigval = eval { no integer; int( $args{sigval} * 60 ) }; $self->sigexpiration( $sigin + $sigval ); } unless ($data) { # mark packet for SIG0 generation $self->{private} = $private; return $self; } my $sigdata = $self->_CreateSigData($data); $self->_CreateSig( $sigdata, $private ); return $self; } sub verify { my ( $self, $dataref, $keyref ) = @_; # Reminder... # $dataref may be either a data string or a reference to a # Net::DNS::Packet object. # # $keyref is either a key object or a reference to an array # of keys. if ( my $isa = ref($dataref) ) { print "First argument is of class $isa\n" if $debug; croak "verify argument can not be $isa" unless $isa =~ /Net::DNS::/; croak 'SIG RR deprecated except for SIG0' unless $dataref->isa('Net::DNS::Packet'); } print "Second argument is of class ", ref($keyref), "\n" if $debug; if ( ref($keyref) eq "ARRAY" ) { # We will recurse for each key that matches algorithm and key-id # we return when there is a successful verification. # If not, we'll continue so that we even survive key-id collision. # The downside of this is that the error string only matches the # last error. my $errorstring = ""; print "Iterating over ", scalar @$keyref, " keys\n" if $debug; my $i = 0; foreach my $keyrr (@$keyref) { $i++; unless ( $self->algorithm == $keyrr->algorithm ) { print "key $i: algorithm does not match\n" if $debug; $errorstring .= "key $i: algorithm does not match "; next; } unless ( $self->keytag == $keyrr->keytag ) { print "key $i: keytag does not match (", $keyrr->keytag, " ", $self->keytag, ")\n" if $debug; $errorstring .= "key $i: keytag does not match "; next; } my $result = $self->verify( $dataref, $keyrr ); print "key $i: ", $self->{vrfyerrstr} if $debug; return $result if $result; $errorstring .= "key $i:" . $self->vrfyerrstr . " "; } $self->{"vrfyerrstr"} = $errorstring; return (0); } elsif ( $keyref->isa('Net::DNS::RR::DNSKEY') || $keyref->isa('Net::DNS::RR::KEY') ) { print "Validating using key with keytag: ", $keyref->keytag, "\n" if $debug; } else { $self->{vrfyerrstr} = join ' ', ref($keyref), 'can not be used as SIG0 key'; return (0); } $self->{vrfyerrstr} = "---- Unknown Error Condition ------"; if ($debug) { print "\n ------------------------------- SIG DEBUG ------------------"; print "\n SIG:\t", $self->string; print "\n KEY:\t", $keyref->string; print "\n --------------------------------------------------------------\n"; } croak "Trying to verify SIG0 using non-SIG0 signature" unless $self->typecovered eq 'TYPE0'; if ( $self->algorithm != $keyref->algorithm ) { $self->{vrfyerrstr} = join ' ', 'signature created using algorithm', $self->algorithm, 'can not be verified using algorithm', $keyref->algorithm; return 0; } # The data that is to be verified my $sigdata = $self->_CreateSigData($dataref); my $signature = $self->sigbin; my $verified = $self->_VerifySig( $sigdata, $signature, $keyref ) || return 0; # time to do some time checking. my $t = time; if ( _ordered( $self->{sigexpiration}, $t ) ) { $self->{vrfyerrstr} = join ' ', 'Signature expired at', $self->sigexpiration; return 0; } elsif ( _ordered( $t, $self->{siginception} ) ) { $self->{vrfyerrstr} = join ' ', 'Signature valid from', $self->siginception; return 0; } $self->{vrfyerrstr} = 'No Error'; return 1; } #END verify sub vrfyerrstr { my $self = shift; $self->{vrfyerrstr} || ''; } ######################################## sub _ordered($$) { ## irreflexive 32-bit partial ordering use integer; my ( $a, $b ) = @_; return defined $b unless defined $a; # ( undef, any ) return 0 unless defined $b; # ( any, undef ) # unwise to assume 32-bit arithmetic, or that integer overflow goes unpunished if ( $a < 0 ) { # translate $a<0 region $a = ( $a ^ 0x80000000 ) & 0xFFFFFFFF; # 0 <= $a < 2**31 $b = ( $b ^ 0x80000000 ) & 0xFFFFFFFF; # -2**31 <= $b < 2**32 } return $a < $b ? ( $a > ( $b - 0x80000000 ) ) : ( $b < ( $a - 0x80000000 ) ); } my $y1998 = timegm( 0, 0, 0, 1, 0, 1998 ); my $y2026 = timegm( 0, 0, 0, 1, 0, 2026 ); my $y2082 = $y2026 << 1; my $y2054 = $y2082 - $y1998; sub _string2time { ## parse time specification string my $arg = shift; croak 'undefined time' unless defined $arg; return int($arg) if length($arg) < 12; my ( $y, $m, @dhms ) = unpack 'a4 a2 a2 a2 a2 a2', $arg . '00'; unless ( $arg gt '20380119031407' ) { # calendar folding return timegm( reverse(@dhms), $m - 1, $y ) if $y < 2026; return timegm( reverse(@dhms), $m - 1, $y - 56 ) + $y2026; } elsif ( $y > 2082 ) { my $z = timegm( reverse(@dhms), $m - 1, $y - 84 ); # expunge 29 Feb 2100 return $z < 1456790400 ? $z + $y2054 : $z + $y2054 - 86400; } return ( timegm( reverse(@dhms), $m - 1, $y - 56 ) + $y2054 ) - $y1998; } sub _time2string { ## format time specification string my $arg = shift; croak 'undefined time' unless defined $arg; unless ( $arg < 0 ) { my ( $yy, $mm, @dhms ) = reverse( ( gmtime $arg )[0 .. 5] ); return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1900, $mm + 1, @dhms; } elsif ( $arg > $y2082 ) { $arg += 86400 unless $arg < $y2054 + 1456704000; # expunge 29 Feb 2100 my ( $yy, $mm, @dhms ) = reverse( ( gmtime( $arg - $y2054 ) )[0 .. 5] ); return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1984, $mm + 1, @dhms; } my ( $yy, $mm, @dhms ) = reverse( ( gmtime( $arg - $y2026 ) )[0 .. 5] ); return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1956, $mm + 1, @dhms; } sub _CreateSigData { my ( $self, $rawdata ) = @_; if ( ref($rawdata) ) { die 'missing packet reference' unless $rawdata->isa('Net::DNS::Packet'); my $packet = $rawdata; my $original = $packet->{additional}; my @unsigned = grep ref($_) ne ref($self), @$original; $packet->{additional} = \@unsigned; # strip signature RR $rawdata = $packet->data; $packet->{additional} = $original; # reinstate signature RR } my @field = qw(typecovered algorithm labels orgttl sigexpiration siginception keytag); my $sigdata = pack 'n C2 N3 n a*', @{$self}{@field}, $self->{signame}->encode; print "preamble:\t", unpack( 'H*', $sigdata ) if $debug; print "\nSIG0 processing\nrawdata:\t", unpack( "H*", $rawdata ), "\n" if $debug; return join '', $sigdata, $rawdata; } ######################################## sub _CreateSig { my $self = shift; my $algorithm = $self->algorithm; return $self->_CreateRSA(@_) if $RSA{$algorithm}; return $self->_CreateDSA(@_) if $DSA{$algorithm}; croak "Algorithm $algorithm not supported"; } sub _VerifySig { my $self = shift; my $algorithm = $self->algorithm; return $self->_VerifyRSA(@_) if $RSA{$algorithm}; return $self->_VerifyDSA(@_) if $DSA{$algorithm}; $self->{vrfyerrstr} = "Algorithm $algorithm not supported"; return 0; } sub _CreateRSA { my ( $self, $sigdata, $private ) = @_; my $hash = $RSA{$private->algorithm} || croak 'private key not RSA'; eval { my $private_rsa = $private->privatekey; $private_rsa->use_pkcs1_oaep_padding; $private_rsa->$hash; $self->sigbin( $private_rsa->sign($sigdata) ); } || croak "RSA Signature generation failed\n\t$@"; } sub _VerifyRSA { my ( $self, $sigdata, $signature, $keyrr ) = @_; # Implementation using Crypt::OpenSSL::RSA print "\nRSA verification called with key:\n\t", $keyrr->string, "\nsig:\n\t", $self->string, "\nsigdata:\n\t", unpack( 'H*', $sigdata ), "\n" if $debug; #RFC 2537 sect 2 my ( $exponent, $modulus ); if ( my $explength = unpack( 'C', my $keybin = $keyrr->keybin ) ) { ( $exponent, $modulus ) = unpack( "x a$explength a*", $keybin ); } else { $explength = unpack( 'xn', $keybin ); ( $exponent, $modulus ) = unpack( "x3 a$explength a*", $keybin ); } my $bn_modulus = Crypt::OpenSSL::Bignum->new_from_bin($modulus); my $bn_exponent = Crypt::OpenSSL::Bignum->new_from_bin($exponent); my $rsa_pub = Crypt::OpenSSL::RSA->new_key_from_parameters( $bn_modulus, $bn_exponent ); die "Could not load public key" unless $rsa_pub; my $hash = $RSA{$self->algorithm}; $rsa_pub->use_pkcs1_oaep_padding; $rsa_pub->$hash; if ( eval { $rsa_pub->verify( $sigdata, $signature ); } ) { $self->{vrfyerrstr} = "RSA Verification successful"; print "\n", $self->{vrfyerrstr}, "\n" if $debug; return 1; } elsif ( my $error = $@ ) { $self->{vrfyerrstr} = "RSA Verification error: $error"; } else { $self->{vrfyerrstr} = "RSA Verification failed"; } print "\n", $self->{vrfyerrstr}, "\n" if $debug; return 0; } sub _CreateDSA { my ( $self, $sigdata, $private ) = @_; my ( $object, @param ) = @{$DSA{$private->algorithm}}; # digest sig data croak 'private key not DSA' unless $object; my $hash = $object->new(@param); $hash->add($sigdata); my $private_dsa = $private->privatekey; if ( my $sig_obj = $private_dsa->do_sign( $hash->digest ) ) { # See RFC 2535 for the content of the SIG my $T = ( length( $private_dsa->get_g ) - 64 ) / 8; my $R = $sig_obj->get_r; my $S = $sig_obj->get_s; # both the R and S parameters need to be 20 octets: my $Rpad = 20 - length($R); my $Spad = 20 - length($S); $self->sigbin( pack "C x$Rpad a* x$Spad a*", $T, $R, $S ); } else { croak "DSA Signature generation failed"; } } sub _VerifyDSA { my ( $self, $sigdata, $signature, $keyrr ) = @_; # Implementation using Crypt::OpenSSL print "\nDSA verification called with key:\n", $keyrr->string, " and sig:\n", $self->string, "\n" if $debug; my ( $object, @param ) = @{$DSA{$self->algorithm}}; # digest sig data my $hash = $object->new(@param); $hash->add($sigdata); my $sighash = $hash->digest; # RFC3279 section 2.3.2 # (...) # The DSA public key MUST be ASN.1 DER encoded as an INTEGER; this # encoding shall be used as the contents (i.e., the value) of the # subjectPublicKey component (a BIT STRING) of the # SubjectPublicKeyInfo data element. # (...) my $t = unpack 'C', $keyrr->keybin; my $size = $t * 8 + 64; my ( $q, $p, $g, $pubkey ) = unpack "x a20 a$size a$size a$size", $keyrr->keybin; my $dsa_pub = Crypt::OpenSSL::DSA->new(); $dsa_pub->set_q($q); $dsa_pub->set_g($g); $dsa_pub->set_p($p); $dsa_pub->set_pub_key($pubkey); my ( $r, $s ) = unpack 'x a20 a20', $self->sigbin; my $DSAsig = Crypt::OpenSSL::DSA::Signature->new(); $DSAsig->set_r($r); $DSAsig->set_s($s); if ( my $retval = eval { $dsa_pub->do_verify( $sighash, $DSAsig ); } ) { croak 'Error in DSA do_verify' if $retval == -1; # fix for DSA < 0.14 $self->{vrfyerrstr} = "DSA Verification successful"; print "\n", $self->{vrfyerrstr}, "\n" if $debug; return 1; } elsif ( my $error = $@ ) { $self->{vrfyerrstr} = "DSA Verification error: $error"; } else { $self->{vrfyerrstr} = "DSA Verification failed"; } print "\n", $self->{vrfyerrstr}, "\n" if $debug; return 0; } 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name SIG typecovered algorithm labels orgttl sigexpiration siginception keytag signame signature'); $rrsig = create Net::DNS::RR::SIG( $string, $keypath, sigval => 60 # minutes ); $sigrr->verify($string, $keyrr) || croak $sigrr->vrfyerrstr; $sigrr->verify($packet, $keyrr) || croak $sigrr->vrfyerrstr; =head1 DESCRIPTION Class for DNS digital signature (SIG) resource records. In addition to the regular methods inherited from Net::DNS::RR the class contains a method to sign packets and scalar data strings using private keys (create) and a method for verifying signatures. The SIG RR is an implementation of RFC2931. See L for an implementation of RFC4034. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head2 typecovered $typecovered = $rr->typecovered; The typecovered field identifies the type of the RRset that is covered by this RRSIG record. =head2 algorithm $algorithm = $rr->algorithm; The algorithm number field identifies the cryptographic algorithm used to create the signature. algorithm() may also be invoked as a class method or simple function to perform mnemonic and numeric code translation. =head2 labels $labels = $rr->labels; $rr->labels( $labels ); The labels field specifies the number of labels in the original RRSIG RR owner name. =head2 orgttl $orgttl = $rr->orgttl; $rr->orgttl( $orgttl ); The original TTL field specifies the TTL of the covered RRset as it appears in the authoritative zone. =head2 sigexpiration and siginception time $expiration = $rr->sigexpiration; $inception = $rr->siginception; The signature expiration and inception fields specify a validity time interval for the signature. The value may be specified by a string with format 'yyyymmddhhmmss' or a Perl time() value. =head2 keytag $keytag = $rr->keytag; $rr->keytag( $keytag ); The keytag field contains the key tag value of the KEY RR that validates this signature. =head2 signame $signame = $rr->signame; $rr->signame( $signame ); The signer name field value identifies the owner name of the KEY RR that a validator is supposed to use to validate this signature. =head2 signature $signature = $rr->signature; The Signature field contains the cryptographic signature that covers the SIG RDATA (excluding the Signature field) and the subject data. =head2 sigbin $sigbin = $rr->sigbin; $rr->sigbin( $sigbin ); Binary representation of the cryptographic signature. =head2 create Create a signature over scalar data. use Net::DNS::SEC; $keypath = '/home/olaf/keys/Kbla.foo.+001+60114.private'; $sigrr = create Net::DNS::RR::SIG( $data, $keypath ); $sigrr = create Net::DNS::RR::SIG( $data, $keypath, sigin => 20130901010101 ); $sigrr->print; # Alternatively use Net::DNS::SEC::Private $private = Net::DNS::SEC::Private->new($keypath); $sigrr= create Net::DNS::RR::SIG( $data, $private ); create() is an alternative constructor for a SIG RR object. This method returns a SIG with the signature over the data made with the private key stored in the key file. The first argument is a scalar that contains the data to be signed. The second argument is a string which specifies the path to a file containing the private key as generated with dnssec-keygen, a program that comes with the ISC BIND distribution. The optional remaining arguments consist of ( name => value ) pairs as follows: sigin => 20130901010101, # signature inception sigex => 20130901011101, # signature expiration sigval => 10, # signature validity The sigin and sigex values may be specified as Perl time values or as a string with the format 'yyyymmddhhmmss'. The default for sigin is the time of signing. The sigval argument specifies the signature validity window in minutes ( sigex = sigin + sigval ). Sigval wins if sigex is also specified. By default the signature is valid for 10 minutes. Notes: =over 4 =item * Do not change the name of the file generated by dnssec-keygen, the create method uses the filename as generated by dnssec-keygen to determine the keyowner, algorithm and the keyid (keytag). =back =head2 verify and vrfyerrstr $sigrr->verify( $data, $keyrr ) || croak $sigrr->vrfyerrstr; $sigrr->verify( $data, [$keyrr, $keyrr2, $keyrr3] ) || croak $sigrr->vrfyerrstr; $sigrr->verify( $packet, $keyrr ) || croak $sigrr->vrfyerrstr; The verify() method performs SIG0 verification of the specified data against the signature contained in the $sigrr object itself using the public key in $keyrr. If a reference to a Net::DNS::Packet is supplied, the method performs a SIG0 verification on the packet data. The second argument can either be a Net::DNS::RR::KEYRR object or a reference to an array of such objects. Verification will return successful as soon as one of the keys in the array leads to positive validation. Returns 0 on error and sets $sig->vrfyerrstr =head2 Example $sig0 = $packet->pop('additional'); print $sig0->vrfyerrstr unless $sig0->verify( $packet, $keyrr ); =head1 Remarks The code is not optimized for speed. =head1 TODO If this code is still around in 2100 (not a leapyear) you will need to check for proper handling of times ... =head1 ACKNOWLEDGMENTS Andy Vaskys (Network Associates Laboratories) supplied the code for handling RSA with SHA1 (Algorithm 5). T.J. Mather, , the Crypt::OpenSSL::DSA maintainer, for his quick responses to bug report and feature requests. =cut =head1 COPYRIGHT Copyright (c)2001-2005 RIPE NCC, Olaf M. Kolkman Copyright (c)2007-2008 NLnet Labs, Olaf M. Kolkman Portions Copyright (c)2014 Dick Franks All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, L, RFC4034, RFC3755, RFC2535, RFC2931, RFC3110, RFC3008, L, L =cut Net-DNS-SEC-0.21/RR/RRSIG.pm0000644000175100017510000006770512422405404014345 0ustar willemwillempackage Net::DNS::RR::RRSIG; # # $Id: RRSIG.pm 1277 2014-10-20 07:46:37Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1277 $)[1]; use strict; use base qw(Net::DNS::RR); =head1 NAME Net::DNS::RR::RRSIG - DNS RRSIG resource record =cut use integer; use warnings; use Carp; use MIME::Base64; use Time::Local; use Net::DNS::Parameters; eval { require Crypt::OpenSSL::RSA }; ## optional for simple Net::DNS RR eval { require Crypt::OpenSSL::DSA }; eval { require Crypt::OpenSSL::Bignum }; eval { require Digest::SHA }; eval { require Net::DNS::SEC::Private }; my $debug = 0; sub decode_rdata { ## decode rdata from wire-format octet string my $self = shift; my ( $data, $offset ) = @_; my $limit = $offset + $self->{rdlength}; my @field = qw(typecovered algorithm labels orgttl sigexpiration siginception keytag); @{$self}{@field} = unpack "\@$offset n C2 N3 n", $$data; ( $self->{signame}, $offset ) = decode Net::DNS::DomainName2535( $data, $offset + 18 ); $self->{sigbin} = substr $$data, $offset, $limit - $offset; } sub encode_rdata { ## encode rdata as wire-format octet string my $self = shift; my $sigbin = $self->sigbin || return ''; my @field = qw(typecovered algorithm labels orgttl sigexpiration siginception keytag); pack 'n C2 N3 n a* a*', @{$self}{@field}, $self->{signame}->encode, $sigbin; } sub format_rdata { ## format rdata portion of RR string. my $self = shift; my $base64 = encode_base64 $self->sigbin || return ''; my $line1 = join ' ', map $self->$_, qw(typecovered algorithm labels orgttl); my $line2 = join ' ', map $self->$_, qw(sigexpiration siginception keytag); my $signame = $self->{signame}->string; chomp $base64; return "$line1 (\n$line2 $signame\n$base64 )"; } sub parse_rdata { ## populate RR from rdata in argument list my $self = shift; my @attribute = qw(typecovered algorithm labels orgttl sigexpiration siginception keytag signame); $self->$_( scalar @_ ? shift : () ) for @attribute; $self->signature(@_); } my %RSA = ( '1' => 'use_md5_hash', '5' => 'use_sha1_hash', '7' => 'use_sha1_hash', '8' => 'use_sha256_hash', '10' => 'use_sha512_hash', ); my %DSA = ( '3' => ['Digest::SHA'], '6' => ['Digest::SHA'], ); my %GOST = ( '12' => ['Digest::GOST::CryptoPro'] ); my %ECDSA = ( '13' => ['Digest::SHA', 256], '14' => ['Digest::SHA', 384], ); # # source: http://www.iana.org/assignments/dns-sec-alg-numbers # { my @algbyname = ( ## Reserved => 0, # [RFC4034][RFC4398] 'RSAMD5' => 1, # [RFC3110][RFC4034] 'DH' => 2, # [RFC2539] 'DSA' => 3, # [RFC3755][RFC2536] ## Reserved => 4, # [RFC6725] 'RSASHA1' => 5, # [RFC3110][RFC4034] 'DSA-NSEC3-SHA1' => 6, # [RFC5155] 'RSASHA1-NSEC3-SHA1' => 7, # [RFC5155] 'RSASHA256' => 8, # [RFC5702] ## Reserved => 9, # [RFC6725] 'RSASHA512' => 10, # [RFC5702] ## Reserved => 11, # [RFC6725] 'ECC-GOST' => 12, # [RFC5933] 'ECDSAP256SHA256' => 13, # [RFC6605] 'ECDSAP384SHA384' => 14, # [RFC6605] 'INDIRECT' => 252, # [RFC4034] 'PRIVATEDNS' => 253, # [RFC4034] 'PRIVATEOID' => 254, # [RFC4034] ## Reserved => 255, # [RFC4034] ); my %algbyval = reverse @algbyname; my @algbynum = map { ( $_, 0 + $_ ) } keys %algbyval; # accept algorithm number my %algbyname = map { s /[^A-Za-z0-9]//g; $_ } @algbyname, @algbynum; sub algbyname { my $name = shift; my $key = uc $name; # synthetic key $key =~ s /[^A-Z0-9]//g; # strip non-alphanumerics return $algbyname{$key} || croak "unknown algorithm $name"; } sub algbyval { my $value = shift; return $algbyval{$value} || $value; } } sub typecovered { my $self = shift; $self->{typecovered} = typebyname(shift) if scalar @_; return typebyval( $self->{typecovered} ); } sub algorithm { my ( $self, $arg ) = @_; unless ( ref($self) ) { ## class method or simple function my $argn = pop || croak 'undefined argument'; return $argn =~ /[^0-9]/ ? algbyname($argn) : algbyval($argn); } return $self->{algorithm} unless defined $arg; return algbyval( $self->{algorithm} ) if $arg =~ /MNEMONIC/i; return $self->{algorithm} = algbyname($arg); } sub labels { my $self = shift; $self->{labels} = 0 + shift if scalar @_; return $self->{labels} || 0; } sub orgttl { my $self = shift; $self->{orgttl} = 0 + shift if scalar @_; return $self->{orgttl} || 0; } sub sigexpiration { my $self = shift; $self->{sigexpiration} = _string2time(shift) if scalar @_; _time2string( $self->{sigexpiration} ) if defined wantarray; } sub siginception { my $self = shift; $self->{siginception} = _string2time(shift) if scalar @_; _time2string( $self->{siginception} ) if defined wantarray; } sub keytag { my $self = shift; $self->{keytag} = 0 + shift if scalar @_; return $self->{keytag} || 0; } sub signame { my $self = shift; $self->{signame} = new Net::DNS::DomainName2535(shift) if scalar @_; $self->{signame}->name if defined wantarray; } sub signature { my $self = shift; $self->sigbin( decode_base64( join '', @_ ) ) if scalar @_; encode_base64( $self->sigbin, '' ) if defined wantarray; } sub sig { &signature; } sub sigbin { my $self = shift; $self->{sigbin} = shift if scalar @_; $self->{sigbin} || ""; } sub create { my ( $class, $datarrset, $priv_key, %args ) = @_; my $private = ref($priv_key) ? $priv_key : Net::DNS::SEC::Private->new($priv_key); croak 'Unable to parse private key' unless ref($private) eq 'Net::DNS::SEC::Private'; croak '$datarrset argument is not a reference to an array' unless ref($datarrset) =~ /ARRAY/; my $RR = $datarrset->[0] || {}; croak '$datarrset is not a reference to an array of RRs' unless ref($RR) =~ /Net::DNS::RR/; # All the TTLs need to be the same in the data RRset. my $ttl = $RR->ttl; my @ttl = grep $_->ttl != $ttl, @$datarrset; croak 'RRs in RRset have different TTLs' if scalar @ttl; my @label = grep $_ ne chr(42), $RR->{owner}->_wire; # count labels my $self = new Net::DNS::RR( name => $RR->name, type => 'RRSIG', class => 'IN', ttl => defined $args{ttl} ? $args{ttl} : $ttl, typecovered => $RR->type, labels => scalar @label, orgttl => $ttl, siginception => $args{sigin} || time(), sigexpiration => $args{sigex} || 0, algorithm => $private->algorithm, keytag => $private->keytag, signame => $private->signame, ); $args{sigval} ||= 30 unless $self->{sigexpiration}; if ( $args{sigval} ) { my $sigin = $self->{siginception}; my $sigval = eval { no integer; int( $args{sigval} * 86400 ) }; $self->sigexpiration( $sigin + $sigval ); } my $sigdata = $self->_CreateSigData($datarrset); $self->_CreateSig( $sigdata, $private ); return $self; } sub verify { my ( $self, $dataref, $keyref ) = @_; # Reminder... # $dataref must be a reference to an array of RR objects. # $keyref is either a reference to an array of keys or a a key object. my $sigzero_verify = 0; my $packet_verify = 0; my $rrarray_verify = 0; my $algorithm = $self->algorithm; my $keyrr; # This will be used to store the key # against which we want to verify. print "Second argument is of class ", ref($keyref), "\n" if $debug; if ( ref($keyref) eq "ARRAY" ) { # We will recurse for each key that matches algorithm and key-id # we return when there is a successful verification. # If not we'll continue so that we even survive key-id collision. # The downside of this is that the error string only matches the # last error. my @keyarray = @{$keyref}; my $errorstring = ""; my $i = 0; print "Iterating over " . @keyarray . " keys \n" if $debug; foreach my $keyrr (@keyarray) { $i++; unless ( $algorithm == $keyrr->algorithm ) { print "key $i: algorithm does not match\n" if $debug; $errorstring .= "key $i: algorithm does not match "; next; } unless ( $self->keytag == $keyrr->keytag ) { print "key $i: keytag does not match (", $keyrr->keytag, " ", $self->keytag, ")\n" if $debug; $errorstring .= "key $i: keytag does not match "; next; } my $result = $self->verify( $dataref, $keyrr ); print "key $i:" . $self->{vrfyerrstr} if $debug; return $result if $result; $errorstring .= "key $i:" . $self->vrfyerrstr . " "; } $self->{vrfyerrstr} = $errorstring; return (0); } elsif ( ref($keyref) eq 'Net::DNS::RR::DNSKEY' || ref($keyref) eq 'Net::DNS::RR::KEY' ) { # we are liberal... # substitute and continue processing after this conditional $keyrr = $keyref; print "Validating using key with keytag: ", $keyrr->keytag, "\n" if $debug; } else { $self->{vrfyerrstr} = "You are trying to pass " . ref($keyref) . " data for a key"; return (0); } print "Verifying data of class: ", ref($dataref), "\n" if $debug; $sigzero_verify = 1 unless ref($dataref); if ( !$sigzero_verify ) { if ( ref($dataref) eq "ARRAY" ) { if ( ref( $dataref->[0] ) and $dataref->[0]->isa('Net::DNS::RR') ) { $rrarray_verify = 1; } else { die "Trying to verify an array of " . ref( $dataref->[0] ) . "\n"; } } elsif ( ref($dataref) and $dataref->isa("Net::DNS::Packet") ) { $packet_verify = 1; die "Trying to verify a packet using non-SIG0 signature" unless $self->{typecovered}; } else { die "Do not know what kind of data this is: " . ref($dataref) . ")\n"; } } $self->{vrfyerrstr} = "---- Unknown Error Condition ------"; if ($debug) { print "\n ------------------------------- RRSIG DEBUG ------------------"; print "\n Reference:\t", ref($dataref); print "\n RRSIG:\t", $self->string; if ($rrarray_verify) { print "\n DATA:\t\t", $_->string for @{$dataref}; } print "\n KEY:\t\t", $keyrr->string; print "\n --------------------------------------------------------------\n"; } if ( !$sigzero_verify && !$packet_verify && $dataref->[0]->type ne $self->typecovered ) { $self->{vrfyerrstr} = join ' ', 'Cannot verify datatype', $dataref->[0]->type, 'with key intended for', $self->typecovered, 'verification'; return 0; } if ( $rrarray_verify && !$dataref->[0]->type eq "RRSIG" ) { # if [0] has type RRSIG the whole RRset is type RRSIG. # There are no SIGs over SIG RRsets $self->{vrfyerrstr} = "RRSIGs over RRSIGs???\nThis is not possible.\n"; return 0; } if ( $algorithm != $keyrr->algorithm ) { $self->{vrfyerrstr} = join ' ', 'signature created using algorithm', $algorithm, 'can not be verified using algorithm', $keyrr->algorithm; return 0; } if ($packet_verify) { my $clone = bless {%$dataref}, ref($dataref); # shallow clone my @addnl = grep $_ != $self, @{$dataref->{additional}}; $clone->{additional} = \@addnl; # without SIG RR my @part = qw(question answer authority additional); my @size = map scalar( @{$clone->{$_}} ), @part; $dataref = pack 'n6', $clone->{ident}, $clone->{status}, @size; foreach my $rr ( map @{$clone->{$_}}, @part ) { $dataref .= $rr->canonical; } } # The data that is to be verified my $sigdata = $self->_CreateSigData($dataref); my $signature = $self->sigbin; my $verified = $self->_VerifySig( $sigdata, $signature, $keyrr ) || return 0; # time to do some time checking. my $t = time; if ( _ordered( $self->{sigexpiration}, $t ) ) { $self->{vrfyerrstr} = join ' ', 'Signature expired at', $self->sigexpiration; return 0; } elsif ( _ordered( $t, $self->{siginception} ) ) { $self->{vrfyerrstr} = join ' ', 'Signature valid from', $self->siginception; return 0; } $self->{vrfyerrstr} = 'No Error'; return 1; } #END verify sub vrfyerrstr { my $self = shift; $self->{vrfyerrstr} || ''; } ######################################## sub _ordered($$) { ## irreflexive 32-bit partial ordering use integer; my ( $a, $b ) = @_; return defined $b unless defined $a; # ( undef, any ) return 0 unless defined $b; # ( any, undef ) # unwise to assume 32-bit arithmetic, or that integer overflow goes unpunished if ( $a < 0 ) { # translate $a<0 region $a = ( $a ^ 0x80000000 ) & 0xFFFFFFFF; # 0 <= $a < 2**31 $b = ( $b ^ 0x80000000 ) & 0xFFFFFFFF; # -2**31 <= $b < 2**32 } return $a < $b ? ( $a > ( $b - 0x80000000 ) ) : ( $b < ( $a - 0x80000000 ) ); } my $y1998 = timegm( 0, 0, 0, 1, 0, 1998 ); my $y2026 = timegm( 0, 0, 0, 1, 0, 2026 ); my $y2082 = $y2026 << 1; my $y2054 = $y2082 - $y1998; sub _string2time { ## parse time specification string my $arg = shift; croak 'undefined time' unless defined $arg; return int($arg) if length($arg) < 12; my ( $y, $m, @dhms ) = unpack 'a4 a2 a2 a2 a2 a2', $arg . '00'; unless ( $arg gt '20380119031407' ) { # calendar folding return timegm( reverse(@dhms), $m - 1, $y ) if $y < 2026; return timegm( reverse(@dhms), $m - 1, $y - 56 ) + $y2026; } elsif ( $y > 2082 ) { my $z = timegm( reverse(@dhms), $m - 1, $y - 84 ); # expunge 29 Feb 2100 return $z < 1456790400 ? $z + $y2054 : $z + $y2054 - 86400; } return ( timegm( reverse(@dhms), $m - 1, $y - 56 ) + $y2054 ) - $y1998; } sub _time2string { ## format time specification string my $arg = shift; croak 'undefined time' unless defined $arg; unless ( $arg < 0 ) { my ( $yy, $mm, @dhms ) = reverse( ( gmtime $arg )[0 .. 5] ); return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1900, $mm + 1, @dhms; } elsif ( $arg > $y2082 ) { $arg += 86400 unless $arg < $y2054 + 1456704000; # expunge 29 Feb 2100 my ( $yy, $mm, @dhms ) = reverse( ( gmtime( $arg - $y2054 ) )[0 .. 5] ); return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1984, $mm + 1, @dhms; } my ( $yy, $mm, @dhms ) = reverse( ( gmtime( $arg - $y2026 ) )[0 .. 5] ); return sprintf '%d%02d%02d%02d%02d%02d', $yy + 1956, $mm + 1, @dhms; } sub _CreateSigData { my ( $self, $rawdata ) = @_; # This method creates the data string that will be signed. # See RFC4034(6) and RFC6840(5.1) on how this string is constructed # This method is called by the method that creates a signature # and by the method that verifies the signature. It is assumed # that the creation method has checked that all the TTLs are # the same for the dataref and that sig->orgttl has been set # to the TTL of the data. This method will set the datarr->ttl # to the sig->orgttl for all the RR in the dataref. print "_CreateSigData\n" if $debug; $self->{typecovered} = 0 unless ref($rawdata); # SIG0 my @field = qw(typecovered algorithm labels orgttl sigexpiration siginception keytag); my $sigdata = pack 'n C2 N3 n a*', @{$self}{@field}, $self->{signame}->encode; print "preamble:\t", unpack( 'H*', $sigdata ) if $debug; unless ( ref($rawdata) ) { # SIG0 case print "\nSIG0 processing\nrawdata:\t", unpack( "H*", $rawdata ), "\n" if $debug; return join '', $sigdata, $rawdata; } my $owner = $self->{owner}; # create wildcard domain name my $limit = $self->{labels}; my @label = $owner->_wire; shift @label while scalar @label > $limit; my $wild = bless {label => \@label}, ref($owner); # DIY to avoid wrecking name cache my $suffix = $wild->encode(0); unshift @label, chr(42); # asterisk my @RR = map bless( {%$_}, ref($_) ), @$rawdata; # shallow RR clone my $RR = $RR[0]; my $class = $RR->class; my $type = $RR->type; my $ttl = $self->orgttl; my %table; foreach my $RR (@RR) { my $ident = $self->{owner}->encode(0); my $match = substr $ident, -length($suffix); croak 'RRs in RRset have different NAMEs' if $match ne $suffix; croak 'RRs in RRset have different TYPEs' if $type ne $RR->type; croak 'RRs in RRset have different CLASS' if $class ne $RR->class; $RR->ttl($ttl); # reset TTL my $offset = 10 + length($suffix); # RDATA offset if ( $ident ne $match ) { $RR->{owner} = $wild; $offset += 2; print "\nsubstituting wildcard name: ", $RR->name if $debug; } # For sorting we create a hash table of canonical data keyed on RDATA my $canonical = $RR->canonical; $table{substr $canonical, $offset} = $canonical; } $sigdata = join '', $sigdata, map $table{$_}, sort keys %table; if ($debug) { my $i = 0; foreach my $rdata ( sort keys %table ) { print "\n>>> ", $i++, "\tRDATA:\t", unpack 'H*', $rdata; print "\nRR: ", unpack( 'H*', $table{$rdata} ), "\n"; } print "\n sigdata:\t", unpack( 'H*', $sigdata ), "\n"; } return $sigdata; } ######################################## sub _CreateSig { my $self = shift; my $algorithm = $self->algorithm; return $self->_CreateRSA(@_) if $RSA{$algorithm}; return $self->_CreateDSA(@_) if $DSA{$algorithm}; croak "Algorithm $algorithm not supported"; } sub _VerifySig { my $self = shift; my $algorithm = $self->algorithm; return $self->_VerifyRSA(@_) if $RSA{$algorithm}; return $self->_VerifyDSA(@_) if $DSA{$algorithm}; $self->{vrfyerrstr} = "Algorithm $algorithm not supported"; return 0; } sub _CreateRSA { my ( $self, $sigdata, $private ) = @_; my $hash = $RSA{$private->algorithm} || croak 'private key not RSA'; eval { my $private_rsa = $private->privatekey; $private_rsa->use_pkcs1_oaep_padding; $private_rsa->$hash; $self->sigbin( $private_rsa->sign($sigdata) ); } || croak "RSA Signature generation failed\n\t$@"; } sub _VerifyRSA { my ( $self, $sigdata, $signature, $keyrr ) = @_; # Implementation using Crypt::OpenSSL::RSA print "\nRSA verification called with key:\n\t", $keyrr->string, "\nsig:\n\t", $self->string, "\nsigdata:\n\t", unpack( 'H*', $sigdata ), "\n" if $debug; #RFC 2537 sect 2 my ( $exponent, $modulus ); if ( my $explength = unpack( 'C', my $keybin = $keyrr->keybin ) ) { ( $exponent, $modulus ) = unpack( "x a$explength a*", $keybin ); } else { $explength = unpack( 'xn', $keybin ); ( $exponent, $modulus ) = unpack( "x3 a$explength a*", $keybin ); } my $bn_modulus = Crypt::OpenSSL::Bignum->new_from_bin($modulus); my $bn_exponent = Crypt::OpenSSL::Bignum->new_from_bin($exponent); my $rsa_pub = Crypt::OpenSSL::RSA->new_key_from_parameters( $bn_modulus, $bn_exponent ); die "Could not load public key" unless $rsa_pub; my $hash = $RSA{$self->algorithm}; $rsa_pub->use_pkcs1_oaep_padding; $rsa_pub->$hash; if ( eval { $rsa_pub->verify( $sigdata, $signature ); } ) { $self->{vrfyerrstr} = "RSA Verification successful"; print "\n", $self->{vrfyerrstr}, "\n" if $debug; return 1; } elsif ( my $error = $@ ) { $self->{vrfyerrstr} = "RSA Verification error: $error"; } else { $self->{vrfyerrstr} = "RSA Verification failed"; } print "\n", $self->{vrfyerrstr}, "\n" if $debug; return 0; } sub _CreateDSA { my ( $self, $sigdata, $private ) = @_; my ( $object, @param ) = @{$DSA{$private->algorithm}}; # digest sig data croak 'private key not DSA' unless $object; my $hash = $object->new(@param); $hash->add($sigdata); my $private_dsa = $private->privatekey; if ( my $sig_obj = $private_dsa->do_sign( $hash->digest ) ) { # See RFC 2535 for the content of the SIG my $T = ( length( $private_dsa->get_g ) - 64 ) / 8; my $R = $sig_obj->get_r; my $S = $sig_obj->get_s; # both the R and S parameters need to be 20 octets: my $Rpad = 20 - length($R); my $Spad = 20 - length($S); $self->sigbin( pack "C x$Rpad a* x$Spad a*", $T, $R, $S ); } else { croak "DSA Signature generation failed"; } } sub _VerifyDSA { my ( $self, $sigdata, $signature, $keyrr ) = @_; # Implementation using Crypt::OpenSSL print "\nDSA verification called with key:\n", $keyrr->string, " and sig:\n", $self->string, "\n" if $debug; my ( $object, @param ) = @{$DSA{$self->algorithm}}; # digest sig data my $hash = $object->new(@param); $hash->add($sigdata); my $sighash = $hash->digest; # RFC3279 section 2.3.2 # (...) # The DSA public key MUST be ASN.1 DER encoded as an INTEGER; this # encoding shall be used as the contents (i.e., the value) of the # subjectPublicKey component (a BIT STRING) of the # SubjectPublicKeyInfo data element. # (...) my $t = unpack 'C', $keyrr->keybin; my $size = $t * 8 + 64; my ( $q, $p, $g, $pubkey ) = unpack "x a20 a$size a$size a$size", $keyrr->keybin; my $dsa_pub = Crypt::OpenSSL::DSA->new(); $dsa_pub->set_q($q); $dsa_pub->set_g($g); $dsa_pub->set_p($p); $dsa_pub->set_pub_key($pubkey); my ( $r, $s ) = unpack 'x a20 a20', $self->sigbin; my $DSAsig = Crypt::OpenSSL::DSA::Signature->new(); $DSAsig->set_r($r); $DSAsig->set_s($s); if ( my $retval = eval { $dsa_pub->do_verify( $sighash, $DSAsig ); } ) { croak 'Error in DSA do_verify' if $retval == -1; # fix for DSA < 0.14 $self->{vrfyerrstr} = "DSA Verification successful"; print "\n", $self->{vrfyerrstr}, "\n" if $debug; return 1; } elsif ( my $error = $@ ) { $self->{vrfyerrstr} = "DSA Verification error: $error"; } else { $self->{vrfyerrstr} = "DSA Verification failed"; } print "\n", $self->{vrfyerrstr}, "\n" if $debug; return 0; } 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name RRSIG typecovered algorithm labels orgttl sigexpiration siginception keytag signame signature'); $rrsig = create Net::DNS::RR::RRSIG( \@rrset, $keypath, sigin => 20130701010101 ); $sigrr->verify( \@rrset, $keyrr ) || croak $sigrr->vrfyerrstr; =head1 DESCRIPTION Class for DNS digital signature (RRSIG) resource records. In addition to the regular methods inherited from Net::DNS::RR the class contains a method to sign RRsets using private keys (create) and a method for verifying signatures over RRsets (verify). The RRSIG RR is an implementation of RFC4034. See L for an implementation of SIG0 (RFC2931). =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head2 typecovered $typecovered = $rr->typecovered; The typecovered field identifies the type of the RRset that is covered by this RRSIG record. =head2 algorithm $algorithm = $rr->algorithm; The algorithm number field identifies the cryptographic algorithm used to create the signature. algorithm() may also be invoked as a class method or simple function to perform mnemonic and numeric code translation. =head2 labels $labels = $rr->labels; $rr->labels( $labels ); The labels field specifies the number of labels in the original RRSIG RR owner name. =head2 orgttl $orgttl = $rr->orgttl; $rr->orgttl( $orgttl ); The original TTL field specifies the TTL of the covered RRset as it appears in the authoritative zone. =head2 sigexpiration and siginception time $expiration = $rr->sigexpiration; $inception = $rr->siginception; The signature expiration and inception fields specify a validity time interval for the signature. The value may be specified by a string with format 'yyyymmddhhmmss' or a Perl time() value. =head2 keytag $keytag = $rr->keytag; $rr->keytag( $keytag ); The keytag field contains the key tag value of the DNSKEY RR that validates this signature. =head2 signame $signame = $rr->signame; The signer name field value identifies the owner name of the DNSKEY RR that a validator is supposed to use to validate this signature. =head2 signature $signature = $rr->signature; The Signature field contains the cryptographic signature that covers the RRSIG RDATA (excluding the Signature field) and the RRset specified by the RRSIG owner name, RRSIG class, and RRSIG type covered fields. =head2 sigbin $sigbin = $rr->sigbin; $rr->sigbin( $sigbin ); Binary representation of the cryptographic signature. =head2 create Create a signature over a RR set. use Net::DNS::SEC; $keypath = '/home/olaf/keys/Kbla.foo.+001+60114.private'; $sigrr = create Net::DNS::RR::RRSIG( \@datarrset, $keypath ); $sigrr = create Net::DNS::RR::RRSIG( \@datarrset, $keypath, sigin => 20130701010101 ); $sigrr->print; #Alternatively use Net::DNS::SEC::Private $private = Net::DNS::SEC::Private->new($keypath); $sigrr= create Net::DNS::RR::RRSIG( \@datarrset, $private ); create() is an alternative constructor for a RRSIG RR object. This method returns an RRSIG with the signature over the datarrset (an array of RRs) made with the private key stored in the key file. The first argument is a reference to an array that contains the RRset that needs to be signed. The second argument is a string which specifies the path to a file containing the private key as generated by dnssec-keygen. The optional remaining arguments consist of ( name => value ) pairs as follows: sigin => 20130701010101, # signature inception sigex => 20130731010101, # signature expiration sigval => 30, # signature validity ttl => 3600 # TTL The sigin and sigex values may be specified as Perl time values or as a string with the format 'yyyymmddhhmmss'. The default for sigin is the time of signing. The sigval argument specifies the signature validity window in days ( sigex = sigin + sigval ). Sigval wins if sigex is also specified. By default the signature is valid for 30 days. By default the TTL matches the RRSet that is presented for signing. Only RSA signatures (algorithms 1,5,7,8 and 10) and DSA signatures (algorithms 3 and 6) have been implemented. =head2 verify and vrfyerrstr $sigrr->verify( $dataref, $keyrr ) || croak $sigrr->vrfyerrstr; $sigrr->verify( $dataref, [$keyrr, $keyrr2, $keyrr3] ) || croak $sigrr->vrfyerrstr; $dataref contains a reference to an array of RR objects and the method verifies the RRset against the signature contained in the $sigrr object itself using the public key in $keyrr. The second argument can either be a Net::DNS::RR::KEYRR object or a reference to an array of such objects. Verification will return successful as soon as one of the keys in the array leads to positive validation. Returns 0 on error and sets $sig->vrfyerrstr =head2 Example print $sigrr->vrfyerrstr unless $sigrr->verify( $rrset, $keyrr ); =head1 KEY GENERATION Private key files and corresponding public DNSKEY records are most conveniently generated using dnssec-keygen, a program that comes with the ISC BIND distribution. dnssec-keygen -a 10 -b 2048 -f ksk rsa.example. dnssec-keygen -a 10 -b 1024 rsa.example.com. dnssec-keygen -a 14 -f ksk ecdsa.example. dnssec-keygen -a 14 ecdsa.example. Do not change the name of the file generated by dnssec-keygen. The create method uses the filename to determine the keyowner, algorithm and the keyid (keytag). =head1 REMARKS The code is not optimized for speed. It is probably not suitable to be used for signing large zones. If this code is still around in 2100 (not a leapyear) you will need to check for proper handling of times ... =head1 ACKNOWLEDGMENTS Andy Vaskys (Network Associates Laboratories) supplied the code for handling RSA with SHA1 (Algorithm 5). T.J. Mather, , the Crypt::OpenSSL::DSA maintainer, for his quick responses to bug report and feature requests. =cut =head1 COPYRIGHT Copyright (c)2001-2005 RIPE NCC, Olaf M. Kolkman Copyright (c)2007-2008 NLnet Labs, Olaf M. Kolkman Portions Copyright (c)2014 Dick Franks All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, L, RFC4034, RFC6840, RFC3755, L, L L BIND 9 Administrator Reference Manual =cut Net-DNS-SEC-0.21/RR/NSEC3.pm0000644000175100017510000002434512422405404014263 0ustar willemwillempackage Net::DNS::RR::NSEC3; # # $Id: NSEC3.pm 1271 2014-10-10 21:55:38Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1271 $)[1]; use strict; use base qw(Net::DNS::RR::NSEC); =head1 NAME Net::DNS::RR::NSEC3 - DNS NSEC3 resource record =cut use integer; use warnings; use Carp; use MIME::Base32; use base qw(Exporter); use vars qw(@EXPORT_OK); @EXPORT_OK = qw(name2hash); require Net::DNS::DomainName; eval { require Digest::SHA }; ## optional for simple Net::DNS RR my %digest = ( '1' => ['Digest::SHA', 1], # RFC3658 ); { my @digestbyname = ( 'SHA-1' => 1, # RFC3658 ); my @digestbyalias = ( 'SHA' => 1 ); my %digestbyval = reverse @digestbyname; my @digestbynum = map { ( $_, 0 + $_ ) } keys %digestbyval; # accept algorithm number my %digestbyname = map { s /[^A-Za-z0-9]//g; $_ } @digestbyalias, @digestbyname, @digestbynum; sub digestbyname { my $name = shift; my $key = uc $name; # synthetic key $key =~ s /[^A-Z0-9]//g; # strip non-alphanumerics return $digestbyname{$key} || croak "unknown digest type $name"; } sub digestbyval { my $value = shift; return $digestbyval{$value} || $value; } } sub decode_rdata { ## decode rdata from wire-format octet string my $self = shift; my ( $data, $offset ) = @_; my $limit = $offset + $self->{rdlength}; my $ssize = unpack "\@$offset x4 C", $$data; @{$self}{qw(algorithm flags iterations saltbin)} = unpack "\@$offset CCnx a$ssize", $$data; $offset += 5 + $ssize; my $hsize = unpack "\@$offset C", $$data; my $hname = unpack "\@$offset x a$hsize", $$data; $self->hnxtname( MIME::Base32::encode $hname, '' ); $offset += 1 + $hsize; $self->{typebm} = substr $$data, $offset, ( $limit - $offset ); } sub encode_rdata { ## encode rdata as wire-format octet string my $self = shift; return '' unless $self->{typebm}; my $salt = $self->saltbin; my $hash = MIME::Base32::decode uc( $self->hnxtname ); pack 'CCn C a* C a* a*', $self->algorithm, $self->flags, $self->iterations, length($salt), $salt, length($hash), $hash, $self->{typebm}; } sub format_rdata { ## format rdata portion of RR string. my $self = shift; return '' unless $self->{typebm}; join ' ', $self->algorithm, $self->flags, $self->iterations, $self->salt || '-', $self->hnxtname, $self->typelist; } sub parse_rdata { ## populate RR from rdata in argument list my $self = shift; $self->algorithm(shift); $self->flags(shift); $self->iterations(shift); my $salt = shift; $self->salt($salt) unless $salt eq '-'; $self->hnxtname(shift); $self->typelist(@_); } sub defaults() { ## specify RR attribute default values my $self = shift; $self->parse_rdata( 1, 0, 0, '' ); } sub algorithm { my ( $self, $arg ) = @_; unless ( ref($self) ) { ## class method or simple function my $argn = pop || croak 'undefined argument'; return $argn =~ /[^0-9]/ ? digestbyname($argn) : digestbyval($argn); } return $self->{algorithm} unless defined $arg; return digestbyval( $self->{algorithm} ) if $arg =~ /MNEMONIC/i; return $self->{algorithm} = digestbyname($arg); } sub flags { my $self = shift; $self->{flags} = 0 + shift if scalar @_; return $self->{flags} || 0; } sub iterations { my $self = shift; $self->{iterations} = 0 + shift if scalar @_; return $self->{iterations} || 0; } sub salt { my $self = shift; $self->saltbin( pack "H*", map { die "!hex!" if m/[^0-9A-Fa-f]/; $_ } join "", @_ ) if scalar @_; unpack "H*", $self->saltbin() if defined wantarray; } sub saltbin { my $self = shift; $self->{saltbin} = shift if scalar @_; $self->{saltbin} || ""; } sub hnxtname { my $self = shift; return $self->{hnxtname} unless scalar @_; $self->{hnxtname} = lc( shift || '' ); } sub covered { my $self = shift; my $name = lc( shift || '' ); # first test if the domain name is in the NSEC zone. my @domainlabels = new Net::DNS::DomainName($name)->_wire; my ( $ownlabel, @zonelabels ) = $self->{owner}->_wire; my $ownername = lc( $ownlabel || '' ); foreach ( reverse @zonelabels ) { return 0 unless lc($_) eq ( pop(@domainlabels) || '' ); } my $hnxtname = $self->hnxtname; my $hashedname = name2hash( $self->algorithm, $name, $self->iterations, $self->saltbin ); my $hashorder = $ownername cmp $hnxtname; if ( $hashorder < 0 ) { return 0 unless ( $ownername cmp $hashedname ) < 0; return 1 if ( $hashedname cmp $hnxtname ) < 0; } elsif ($hashorder) { # last name in zone return 1 if ( $hashedname cmp $hnxtname ) < 0; return 1 if ( $ownername cmp $hashedname ) < 0; } else { # only name in zone return 1; } return 0; } sub match { my $self = shift; my $name = shift; my ($ownername) = $self->{owner}->_wire; my $hashedname = name2hash( $self->algorithm, $name, $self->iterations, $self->saltbin ); return $hashedname eq lc( $ownername || '' ); } sub optout { my $bit = 0x01; for ( shift->{flags} ||= 0 ) { return $_ & $bit unless scalar @_; my $set = $_ | $bit; $_ = (shift) ? $set : ( $set ^ $bit ); return $_ & $bit; } } ######################################## sub hashalgo { ## historical &algorithm; } sub nxtdname { ## inherited method inapplicable my $method = join '::', __PACKAGE__, 'nxtdname'; confess "method '$method' undefined"; } sub name2hash { my $hashalg = shift; my $name = lc( shift || '' ); my $iterations = shift || 0; my $salt = shift || ''; my $arglist = $digest{$hashalg} || die 'unsupported hash algorithm'; my ( $object, @argument ) = @$arglist; my $hash = $object->new(@argument); my $wirename = new Net::DNS::DomainName($name)->encode; $iterations++; while ( $iterations-- > 0 ) { $hash->add($wirename); $hash->add($salt); $wirename = $hash->digest; } my $base32hex = MIME::Base32::encode( $wirename, '' ); # [0-9 A-V] per RFC4648, 7. return lc $base32hex; } 1; __END__ =head1 SYNOPSIS use Net::DNS; $rr = new Net::DNS::RR('name NSEC3 algorithm flags iterations salt hnxtname'); =head1 DESCRIPTION Class for DNSSEC NSEC3 resource records. The NSEC3 Resource Record (RR) provides authenticated denial of existence for DNS Resource Record Sets. The NSEC3 RR lists RR types present at the original owner name of the NSEC3 RR. It includes the next hashed owner name in the hash order of the zone. The complete set of NSEC3 RRs in a zone indicates which RRSets exist for the original owner name of the RR and form a chain of hashed owner names in the zone. =head1 METHODS The available methods are those inherited from the base class augmented by the type-specific methods defined in this package. Use of undocumented package features or direct access to internal data structures is discouraged and could result in program termination or other unpredictable behaviour. =head2 algorithm $algorithm = $rr->algorithm; $rr->algorithm( $algorithm ); The Hash Algorithm field is represented as an unsigned decimal integer. The value has a maximum of 255. algorithm() may also be invoked as a class method or simple function to perform mnemonic and numeric code translation. =head2 flags $flags = $rr->flags; $rr->flags( $flags ); The Flags field is represented as an unsigned decimal integer. The value has a maximum value of 255. =head2 iterations $iterations = $rr->iterations; $rr->iterations( $iterations ); The Iterations field is represented as an unsigned decimal integer. The value is between 0 and 65535, inclusive. =head2 salt $salt = $rr->salt; $rr->salt( $salt ); The Salt field is represented as a contiguous sequence of hexadecimal digits. A "-" (unquoted) is used in string format to indicate that the salt field is absent. =head2 saltbin $saltbin = $rr->saltbin; $rr->saltbin( $saltbin ); The Salt field as a sequence of octets. =head2 hnxtname $hnxtname = $rr->hnxtname; $rr->hnxtname( $hnxtname ); The Next Hashed Owner Name field points to the next node that has authoritative data or contains a delegation point NS RRset. =head2 typelist @typelist = $rr->typelist; $typelist = $rr->typelist; $rr->typelist( @typelist ); The Type List identifies the RRset types that exist at the NSEC RR owner name. When called in scalar context, the list is interpolated into a string. =head2 covered, matched print "covered" if $rr->covered{'example.foo'} covered() returns a nonzero value when the the domain name provided as argument is covered as defined in the NSEC3 specification: To cover: An NSEC3 RR is said to "cover" a name if the hash of the name or "next closer" name falls between the owner name and the next hashed owner name of the NSEC3. In other words, if it proves the nonexistence of the name, either directly or by proving the nonexistence of an ancestor of the name. Similarly matched() returns a nonzero value when the domainname in the argument matches as defined in the NSEC3 specification: To match: An NSEC3 RR is said to "match" a name if the owner name of the NSEC3 RR is the same as the hashed owner name of that name. =head2 optout $rr->optout(0); $rr->optout(1); if ( $rr->optout ) { ... } Boolean Opt Out flag. =head1 COPYRIGHT Copyright (c)2007,2008 NLnet Labs. Author Olaf M. Kolkman All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Package template (c)2009,2012 O.M.Kolkman and R.W.Franks. =head1 SEE ALSO L, L, L, RFC5155 L =cut Net-DNS-SEC-0.21/META.yml0000664000175100017510000000141112422405450014030 0ustar willemwillem--- abstract: 'DNSSEC extensions to Net::DNS' author: - 'Olaf M. Kolkman ' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.120351' license: mit meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Net-DNS-SEC no_index: directory: - t - inc requires: Crypt::OpenSSL::Bignum: 0.03 Crypt::OpenSSL::DSA: 0.1 Crypt::OpenSSL::RSA: 0.19 Crypt::OpenSSL::Random: 0 Digest::BubbleBabble: 0.01 Digest::SHA: 5.23 File::Basename: 0 MIME::Base32: 0 MIME::Base64: 0 Math::BigInt: 0 Net::DNS: 0.69 Test::More: 0.47 Time::Local: 0 perl: 5.006 version: 0.21 Net-DNS-SEC-0.21/TODO0000644000175100017510000000034512422405404013251 0ustar willemwillemTODO for Net::DNS::SEC package. ---------------------------------------------------------------------- Last modified for version 0.12_1 ---------------------------------------------------------------------- - Code cleanup Net-DNS-SEC-0.21/MANIFEST0000644000175100017510000000147212422405450013715 0ustar willemwillemChanges demo/getkeyset.pl demo/key2ds demo/make-signed-keyset Keyset.pm Makefile.PL MANIFEST This list of files META.yml README RR/DNSKEY.pm RR/DS.pm RR/KEY.pm RR/NSEC.pm RR/NSEC3.pm RR/NSEC3PARAM.pm RR/RRSIG.pm RR/SIG.pm RR/CDNSKEY.pm RR/CDS.pm RR/DLV.pm SEC.pm SEC/Private.pm t/00-load.t t/00-pod.t t/05-DLV.t t/05-DNSKEY.t t/05-DS.t t/05-KEY.t t/05-NSEC.t t/05-NSEC3.t t/05-NSEC3PARAM.t t/05-RRSIG.t t/05-SIG.t t/07-sec.t t/09-dnssec.t t/10-keyset.t t/10-typeroll.t t/11-sep.t t/11-sigstress.t t/12-nsec++.t t/13-utilities.t t/51-DS-SHA1.t t/52-DS-SHA256.t t/53-DS-GOST.t t/54-DS-SHA384.t t/getpacket.pl t/Kexample.com.+001+28551.private t/Kexample.com.+001+28551.key t/Kexample.com.+005+34247.key t/Kexample.com.+005+34247.private TODO META.json Module JSON meta-data (added by MakeMaker) Net-DNS-SEC-0.21/SEC.pm0000644000175100017510000000730412422405404013533 0ustar willemwillempackage Net::DNS::SEC; # # $Id: SEC.pm 1280 2014-10-24 08:15:06Z willem $ # use vars qw($VERSION $SVNVERSION); $VERSION = '0.21'; $SVNVERSION = (qw$LastChangedRevision: 1280 $)[1]; =head1 NAME Net::DNS::SEC - DNSSEC extensions to Net::DNS =head1 SYNOPSIS use Net::DNS::SEC; =head1 DESCRIPTION The Net::DNS::SEC suite provides the additional DNS resource records required to support DNSSEC as described in RFC4033, 4034, 4035 and subsequent related documents. Net::DNS::SEC is installed as an extension to an existing Net::DNS installation. The extended package features are made visible by substituting Net::DNS::SEC for Net::DNS in the use declaration. =cut use strict; use base qw(Exporter); use Net::DNS 0.69 qw(:DEFAULT); use vars qw(@EXPORT); @EXPORT = ( @Net::DNS::EXPORT, qw(algorithm digtype key_difference) ); use integer; use warnings; use Carp; require Net::DNS::RR::DS; new Net::DNS::RR( type => $_ ) for qw(SIG RRSIG DS CDS DLV); # pre-load RR with create() constructor =head1 UTILITY FUNCTIONS =head2 algorithm $mnemonic = algorithm( 5 ); $numeric = algorithm( 'RSA-SHA1' ); print "algorithm mnemonic\t", $mnemonic, "\n"; print "algorithm number:\t", $numeric, "\n"; algorithm() provides conversions between an algorithm code number and the corresponding mnemonic. =cut sub algorithm { &Net::DNS::RR::DS::algorithm; } =head2 digtype $mnemonic = digtype( 2 ); $numeric = digtype( 'SHA-256' ); print "digest type mnemonic\t", $mnemonic, "\n"; print "digest type number:\t", $numeric, "\n"; digtype() provides conversions between a digest type number and the corresponding mnemonic. =cut sub digtype { &Net::DNS::RR::DS::digtype; } =head2 key_difference @result = key_difference( \@a, \@b ); Fills @result with all keys in array @a that are not in array @b. =cut my $errmsg = 'array argument contains unexpected %s object'; sub key_difference { my $a = shift; my $b = shift; my $r = shift; ## 0.17 interface my ($x) = grep !$_->isa('Net::DNS::RR::DNSKEY'), @$a, @$b; if ($r) { ## 0.17 interface return sprintf $errmsg, ref($x) if $x; my %index = map { ( $_->privatekeyname, 1 ) } @$b; @$r = grep { !$index{$_->privatekeyname} } @$a; return (0); } croak sprintf $errmsg, ref($x) if $x; my %index = map { ( $_->privatekeyname, 1 ) } @$b; my @r = grep { !$index{$_->privatekeyname} } @$a; return @r; } 1; __END__ =head1 COPYRIGHT Copyright (c)2001-2005 RIPE NCC. Author Olaf M. Kolkman All Rights Reserved =head1 LICENSE Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. =head1 SEE ALSO L, L, L, L, L, L, L, L, L, L, L, L, L, RFC4033, RFC4034, RFC4035 =cut Net-DNS-SEC-0.21/SEC/0000755000175100017510000000000012422405450013172 5ustar willemwillemNet-DNS-SEC-0.21/SEC/Private.pm0000644000175100017510000003646712422405404015161 0ustar willemwillempackage Net::DNS::SEC::Private; # # $Id: Private.pm 1268 2014-09-29 08:09:00Z willem $ # use vars qw($VERSION); $VERSION = (qw$LastChangedRevision: 1268 $)[1]; =head1 NAME Net::DNS::SEC::Private - DNSSEC Private key object =head1 SYNOPSIS use Net::DNS::SEC::Private; $private = Net::DNS::SEC::Private->new($keypath); =head1 DESCRIPTION Class containing a the private key as read from a dnssec-keygen generated keyfile. The class is written to be used only in the context of the Net::DNS::RR::RRSIG create method. This class is not designed to interact with any other system. =cut use strict; use base qw(Net::DNS::SEC); use integer; use warnings; use Carp; use File::Basename; use MIME::Base64; use Crypt::OpenSSL::Bignum; use Crypt::OpenSSL::Random; use Crypt::OpenSSL::DSA; use Crypt::OpenSSL::RSA; my $debug = 0; sub new { my ($class, $key_file) = @_; my $self={}; my ($Modulus,$PublicExponent,$PrivateExponent,$Prime1, $Prime2,$Exponent1,$Exponent2,$Coefficient, $prime_p,$subprime_q,$base_g,$private_val_x,$public_val_y, $Created, $Publish, $Activate, $Revoke, $Unpublish, $Delete); bless ($self,$class); my $keyname=basename($key_file); print "\nKeyname:\t ". $keyname ."\n" if $ debug; #Format something like: /Kbla.foo.+001+60114.private' # assuming proper file name. # We determine the algorithm from the filename. if ($keyname =~ /K(.*)\.\+(\d{3})\+(\d*)\.private/){ $self->{"signame"}=$1."."; $self->{"algorithm"}= 0 + $2; # Force non-string $self->{"keytag"}=$3; }else{ croak "$keyname does not seem to be a valid private key\n"; } open (KEYFH, "<$key_file" ) || croak "Cannot open keyfile: $key_file"; local $_; while () { if (/Private-key-format: (v\d*\.\d*)/) { if ($1 ne "v1.2" && $1 ne "v1.3") { croak "Private Key Format not recognized"; } }elsif (/^Algorithm:\s*(\d*)/) { if ($1 != 1 && $1 != 3 && $1 != 5 && $1 !=6 && $1 != 7 && $1 != 8 && $1 != 10 ) { croak "Key $key_file algorithm is not RSA or DSA (those are the only implemented algorithms) "; } } elsif (/^Modulus:\s*(\S+)/) { #RSA $Modulus=Crypt::OpenSSL::Bignum->new_from_bin(decode_base64($1)); } elsif (/^PublicExponent:\s*(\S+)/) { $PublicExponent=Crypt::OpenSSL::Bignum->new_from_bin(decode_base64($1)); } elsif (/^PrivateExponent:\s*(\S+)/) { $PrivateExponent=Crypt::OpenSSL::Bignum->new_from_bin(decode_base64($1)); } elsif (/^Prime1:\s*(\S+)/) { $Prime1=Crypt::OpenSSL::Bignum->new_from_bin(decode_base64($1)); } elsif (/^Prime2:\s*(\S+)/) { $Prime2=Crypt::OpenSSL::Bignum->new_from_bin(decode_base64($1)); } elsif (/^Exponent1:\s*(\S+)/) { $Exponent1=Crypt::OpenSSL::Bignum->new_from_bin(decode_base64($1)); } elsif (/^Exponent2:\s*(\S+)/) { $Exponent2=Crypt::OpenSSL::Bignum->new_from_bin(decode_base64($1)); } elsif (/^Coefficient:\s*(\S+)/) { $Coefficient=Crypt::OpenSSL::Bignum->new_from_bin(decode_base64($1)); } elsif (/^Prime\(p\):\s*(\S+)/) { #DSA $prime_p=decode_base64($1); } elsif (/^Subprime\(q\):\s*(\S+)/) { $subprime_q=decode_base64($1); } elsif (/^Base\(g\):\s*(\S+)/) { $base_g=decode_base64($1); } elsif (/^Private_value\(x\):\s*(\S+)/) { $private_val_x=decode_base64($1); } elsif (/^Public_value\(y\):\s*(\S+)/) { $public_val_y=decode_base64($1); } elsif (/^Created\(y\):\s*(\S+)/) { $Created=$1; } elsif (/^Publish\(y\):\s*(\S+)/) { $Publish=$1; } elsif (/^Activate\(y\):\s*(\S+)/) { $Activate=$1; } elsif (/^Revoke\(y\):\s*(\S+)/) { $Revoke=$1; } elsif (/^Unpublish\(y\):\s*(\S+)/) { $Unpublish=$1; } elsif (/^Delete\(y\):\s*(\S+)/) { $Delete=$1; } } close(KEYFH); if ($self->{"algorithm"} == 1 || $self->{"algorithm"} == 5 || $self->{"algorithm"} == 7 || $self->{"algorithm"} == 8 || $self->{"algorithm"} == 10) { #RSA $self->{'privatekey'}=Crypt::OpenSSL::RSA-> new_key_from_parameters( $Modulus, $PublicExponent, $PrivateExponent, $Prime1, $Prime2, $Exponent1, $Exponent2, $Coefficient, ); # Trying to determine the keytag my $keytag_from_data1=$self->dump_rsa_keytag(256,1); my $keytag_from_data2=$self->dump_rsa_keytag(257,1); if (($self->{"keytag"} != $keytag_from_data1) && ($self->{"keytag"} != $keytag_from_data2)){ warn "NB: filename seems to have the wrong keytag.\n". "Depending on DNSKEY RR flags set for this key the keytag should be\n". $keytag_from_data1. " or ". $keytag_from_data2. " instead of ".$self->{"keytag"}."\n"; return(0); } }elsif ($self->{"algorithm"} == 3 || $self->{"algorithm"} == 6 ){ #DSA my $private_dsa = Crypt::OpenSSL::DSA->new(); $private_dsa->set_p($prime_p); $private_dsa->set_q($subprime_q); $private_dsa->set_g($base_g); $private_dsa->set_priv_key($private_val_x); $private_dsa->set_pub_key($public_val_y); $self->{"privatekey"}=$private_dsa; } if (defined($Created)) { # new fields in v1.3 $self->{'created'} = $Created; $self->{'publish'} = $Publish; $self->{'activate'} = $Activate; $self->{'revoke'} = $Revoke; $self->{'unpublish'} = $Unpublish; $self->{'delete'} = $Delete; } return $self; } sub privatekey { my $self=shift; return $self->{'privatekey'}; } sub keytag { my $self=shift; return $self->{'keytag'}; } sub signame { my $self=shift; return $self->{'signame'}; } sub created { my $self=shift; return $self->{'created'} if (exists($self->{'created'})); } sub publish { my $self=shift; return $self->{'publish'} if (exists($self->{'publish'})); } sub activate { my $self=shift; return $self->{'activate'} if (exists($self->{'activate'})); } # Little helper function to put a BigInt into a binary (unsigned, #network order ) #sub bi2bin { # my($p, $l) = @_; # $l ||= 0; # my $base = Math::BigInt->new("+256"); # my $res = ''; # { # my $r = $p % $base; # my $d = ($p-$r) / $base; # $res = chr($r) . $res; # if ($d >= $base) { # $p = $d; # redo; # } # elsif ($d != 0) { # $res = chr($d) . $res; # } # } # $res = "\0" x ($l-length($res)) . $res # if length($res) < $l; # $res; #} sub new_rsa_priv { my ($class, $keyblob,$signame,$flags,$algorithm) = @_; my $self={}; bless ($self,$class); $self->{"signame"}=$signame; if (defined($algorithm)) { $self->{"algorithm"} = $self->algorithm($algorithm); } else { $self->{"algorithm"} = 5; } $self->{"flags"}=$flags; $self->{'privatekey'}=Crypt::OpenSSL::RSA-> new_private_key($keyblob); $self->{"keytag"}=$self->dump_rsa_keytag(); return $self; } sub dump_rsa_priv { my $self=shift; my ( $Modulus,$PublicExponent, $PrivateExponent, $Prime1, $Prime2, $Exponent1, $Exponent2,$Coefficient )=$self->{"privatekey"}->get_key_parameters; my $string="Private-key-format: v1.2\n"; $string .= "Algorithm: " . $self->{"algorithm"} . " (" . $self->algorithm("mnemonic") . ")\n"; if (defined $Modulus && defined $PublicExponent && defined $PrivateExponent && defined $Prime1 && defined $Prime2 && defined $Exponent1 && defined $Exponent2 && $Coefficient ){ $string .= "Modulus: ". encode_base64($Modulus->to_bin,"")."\n" ; $string .= "PublicExponent: ". encode_base64($PublicExponent->to_bin,"")."\n" ; $string .= "PrivateExponent: ". encode_base64($PrivateExponent->to_bin,"")."\n"; $string .= "Prime1: ". encode_base64($Prime1->to_bin,"")."\n" ; $string .= "Prime2: ". encode_base64($Prime2->to_bin,"")."\n" ; $string .= "Exponent1: ". encode_base64($Exponent1->to_bin,"")."\n" ; $string .= "Exponent2: ". encode_base64($Exponent2->to_bin,"")."\n" ; $string .= "Coefficient: ". encode_base64($Coefficient->to_bin,"")."\n" ; } else { $string= ""; }; return $string; } sub dump_rsa_pub { my $self=shift; my ( $Modulus,$PublicExponent, $PrivateExponent, $Prime1, $Prime2, $Exponent1, $Exponent2,$Coefficient )=$self->{"privatekey"}->get_key_parameters; return "" unless (defined $Modulus && defined $PublicExponent); my $explength; my $pubexp=$PublicExponent->to_bin; if (length($pubexp)>255){ $explength=pack("C",0).pack("n",length($pubexp)); }else{ $explength=pack("C",length($pubexp)); } return encode_base64($explength.$pubexp.$Modulus->to_bin, ""); } sub dump_rsa_keytag{ my $self=shift; my $flags; if (defined $self->{"flags"}){ $flags=$self->{"flags"} }else{ $flags=shift; } return() unless defined $flags; # This will set flag if empty before, note the undocumented # feature that a non-zero second argument to this function will # _not_ set the flag. $self->{"flags"}=$flags unless shift; my $alg=$self->{"algorithm"}; return () unless ($alg ==1 || $alg ==5 || $alg == 7 || $alg ==8 || $alg ==10); my $key=$self->dump_rsa_pub; return () unless $key; my $tmprr=Net::DNS::RR->new("tmp IN DNSKEY $flags 3 $alg $key"); return $tmprr->keytag; } sub dump_rsa_private_der { my $self=shift; return $self->{"privatekey"}->get_private_key_string; } sub generate_rsa { my ($class) =shift; my $name=shift; my $flags=shift; my $size=shift; $size=1024 if !defined ($size); my $good_entropy=shift; my $algorithm=shift; if (defined($algorithm)) { $algorithm = $class->algorithm($algorithm); } else { $algorithm = 5; } my $self={}; bless ($self,$class); $self->{"signame"}=$name; $self->{"algorithm"}= $algorithm; # Force non-string if (defined($good_entropy)){ Crypt::OpenSSL::Random::random_seed($good_entropy); Crypt::OpenSSL::RSA->import_random_seed(); } my $rsa = Crypt::OpenSSL::RSA->generate_key($size); $self->{"privatekey"}=$rsa; $self->{"keytag"}=$self->dump_rsa_keytag($flags); return $self; } 1; __END__ =head1 METHODS =head2 new $private->new("/home/foo/ Kexample.com.+001+11567.private") Creator method. The argument is the full path to a private key generated by the BIND dnssec-keygen tool. Note that the filename contains information about the algorithm and keyid. =head2 private $private->private Returns the private key material. This is either a Crypt::OpenSSL::RSA or Crypt::OpenSSL::DSA object. This is really only relevant to the Net::DNS::RR::RRSIG and Net::DNS::RR::SIG classes. =head2 algorithm, keytag, signame, created, publish, activate $private->algorithm $private->keytag $private->signame $private->created $private->publish $private->activate Returns components as determined from the filename and needed by Net::DNS::RR::RRSIG. The 'created', 'publish' and 'activate' components are only available in version 1.3 or higher formatted files. =head1 RSASHA1 specific helper functions These functions may be usefull to read and transfer BIND private keys to and from X509 format. =head2 new_rsa_private Constructor method. my $private=Net::DNS::SEC::Private->new_rsa_private($keyblob,$domain,$flag,$algorithm); Creates a Net::DNS::SEC::Private object from the supplied string. For the object to be useful you will have to provide the "domain" name for which this key is to be used as the second argument and the flag (either 256 or 257 for a non SEP and a SEP key respectivly). The string should include the -----BEGIN...----- and -----END...----- lines. The padding is set to PKCS1_OAEP, but can be changed with the use_xxx_padding methods It is the same =head2 dump_rsa_priv my $bind_keyfilecontent=$private->dump_rsa_priv Returns the content of a BIND private keyfile (Private-key-format: v1.2). An empty string will be returned if not all parameters are available (please supply the author with example code if this ever happens). =head2 dump_rsa_pub my $bind_keyfilecontent=$private->dump_rsa_pub Returns the publick key part of the DNSKEY RR. Returns an empty string on failure. =head2 dump_rsa_keytag my $flags=257; # SEP key. my $keytag=$private->dump_rsa_keytag($flags); This function will calculate the keyt with the value of the DNSKEY flags as input. The flags field may be needed in case it was not specified when the key was created. If the object allready knows it's flags vallue the input is ignored. returns undefined on failure =head2 dump_rsa_private_der my $keyblob=$private->dump_rsa_privat_der Return the DER-encoded PKCS1 representation of the private key. (Same format that can be read with the read_rsa_private method.) =head2 generate_rsa my $keypair=Net::DNS::SEC::Private->generate_rsa("example.com",$flag,1024,$random, $algorithm); prin $newkey->dump_rsa_priv; print $newkey->dump_rsa_pub(); Uses Crypt::OpenSSL::RSA generate_key to create a keypair. First argument is the name of the key, the second argument is the flag field (take a value of 257 for Keysigning keys and a value of 256 for zone signing keys). The 3rd argument is the keysize. If the 4th argument is defined it is passed to the Crypt::OpenSSL::Random::random_seed method (see Crypt::OpenSSL::RSA for details), not needed with a proper /dev/random. =head1 Example This is a code sniplet from the test script. First a new keypair is generated. An Net::DNS::RR object is created by constructing the resource record string - using the dump_rsa_pub() method. Then a self signature over the public key is created and verified. my $newkey=Net::DNS::SEC::Private->generate_rsa("example.com",257,1024); my $tstpubkeyrr= Net::DNS::RR->new ($newkey->signame . " IN DNSKEY 257 3 5 ". $newkey->dump_rsa_pub()); # flags not needed as argument for dump_rsa_keytag $ since they where set by generate_rsa is($tstpubkeyrr->keytag,$newkey->dump_rsa_keytag(), "Consistent keytag calculation"); my $sigrr= create Net::DNS::RR::RRSIG([$tstpubkeyrr],$newkey); is ($sigrr->keytag,$tstpubkeyrr->keytag, "Consisted keytag in the created signature");; ok($sigrr->verify([$tstpubkeyrr],$tstpubkeyrr), "Self verification consistent."); =head1 COPYRIGHT Copyright (c) 2002-2005 RIPE NCC. Author Olaf M. Kolkman All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. This code uses Crypt::OpenSSL which uses the openssl library =head1 SEE ALSO L, L, L, L, L, L, L,L, RFC 2435 Section 4, RFC 2931. =cut Net-DNS-SEC-0.21/Changes0000644000175100017510000003767412422405404014073 0ustar willemwillemRevision history for Perl extension Net::DNS::SEC. ***0.21 Oktober 24, 2014 Fix: rt.cpan.org #99250 [RRSIG] validation fails when Signer's Name is upper case Fix: rt.cpan.org #99106 Premature end of base64 data (in 14-misc.t test script) ***0.20 August 15, 2014 Fix: rt.cpan.org #97457 !hex! error when parsing NSEC3 with empty salt ***0.19 Jun 6, 2014 Remove inappropriate deprecation warning in DNSKEY.pm ***0.18 May 8, 2014 Recode RR implementations to provide Net::DNS 0.69+ interface. Fix: rt.cpan.org #95034 Failure to parse NSEC3PARAM record with null salt Fix: rt.cpan.org #81289 Failure to handle GOST DS records ***0.17 November 29, 2013 Fix: rt.cpan.org #90270 NSEC3->covered() should use case-insensitive comparisons Fix: rt.cpan.org #79606 Lower case zone-name part with DNSKEY::privatename Allow to specify algorithms with ::Private->new_rsa_private and ::Private->generate_rsa instead of assuming RSASHA1. Fix: rt.cpan.org #55621 Specify license type (mit) in META.yml Fix: rt.cpan.org #60269 Remove Digest::SHA1 prerequirement Fix: rt.cpan.org #62387 & #63273 Typo fixes Fix: rt.cpan.org #62386 Make Net::DNS::RR::DS::digtype method work Fix: rt.cpan.org #62385 Do not compress Next Domain Name in NSEC rdata. Fix: rt.cpan.org #61104 Spelling correction in DS.pm and fix of key2ds demo program Fix: rt.cpan.org #60185 Make sure %main::SIG hash keeps its values when compiling Net::DNS::RR::SIG in perl versions before 5.14. See also: rt.perl.org #76138 Fix: rt.cpan.org #64552 and rt.cpan.org #79606 Support for private-key-format v1.3 Fix: rt.cpan.org #75892 Do not canonicalize the "Next Domain Name" rdata field of a NSEC RR for draft-ietf-dnsext-dnssec-bis-updates-17 compliency. BUG FIX/FEATURE: validation of wildcard RRs now available. Duanne Wessels is acknowledged for submitting the initial code on which this fix is based. FIX: case sensitivity of ownername during DS generation (Acknowledgements Jens Wagner) ***0.16 March 12, 2010 Feature: KEY inherits DNSKEY This helps maintenance in one part of the code. Feature: keylength methode rt.cpan.org #53468 Added keylength method for RSA and DSA Acknowledgements Hugo Salgado Fix: rt.cpan.org #51778 Empty bitmap would cause error about undefined ARRAY in NSEC/NSEC3. Now the code will allow empty bitmaps gracefully Feature: New Algorithm Support (rt.cpan.org #51092) SHA2 algorithm support, including NSEC3 algorithm parameters updated Acknowledgement Jakob Shlyter Fix: rt.cpan.org #42089 NSEC3 Algorithm support in NSEC3 broken patch by Wes Hardaker ***0.15 December 31, 2008 Fix: digestbin not set when an empty value passed to hash. Feature: Added DLV (rfcc 4431). The RR object is simply a clone of the DS RR and inherits ... everything Feature: Added NSEC3 and NSEC3PARAM support (RFC5155). This adds Mime::Base32 to the module dependency list. The RR type was still experimental at that time and is maintained in Net::DNS::RR. Fix: Test script recognizes change in Time::Local. Note that Time::Local does not deal with dates beyond 03:14:07 UTC on Tuesday, 19 January 2038. Therefore this code has a year 2038 problem. Fix: DS create_from_hash now produces objects that can create wireformat. Other: minor changes to the debug statements added t/05-rr.t (and identified a couple of bugs using it) Fix: a few inconsistencies with respect to parsing of trailing dots. During development the test signatures generated with the BIND tools were re-generated in order to troubleshoot a bug that (most probably) was caused by a version incompatibility between Net::DNS and Net::DNS::SEC. Before release the original test from the 0.14 release were ran against this version too. 0.14 February 14, 2005 FIX: The introducion of the keytag warning triggered a bug with RSAMD5 keys, causing RSAMD5 keys not to be loaded. 0.13 December 9, 2005 FEAT: rt.cpan.org 14588 Added support for passing (a reference to) an array of keys to the RRSIG verify function. FIX/FEAT: The Net::DNS::SEC::Private function will for RSA based keys verify if the keytag in the filename is actually correct. Since at parsing the value of the DNSKEY RR flags is not known we test against the currently defined flag values 256 and 257. If we cannot find a keytag match a warning is printed and Private key generation fails This inconsistency was spotted by Jakob Shlyter. FEAT: Added support for SHA256 to the DS RR. Assigned the expected digest type2 for SHA256 type hashes. Note that this makes the Net::DNS::SEC depend on Digest::SHA instead of Digest::SHA1. The default digest type is still set to 1. NB. The code makes assumptions about the IANA assignment of the digest type. The assignment may change. Do not use SHA256 in production zones!! FIX: rt.cpan.org #15662 Roy Arends noticed and patched the label counting did not ignore an initial asterisk label. FIX: Wes Hardaker noticed the default TTL values for created signatures to be different from the TTLs from the data that is being signed. FIX: Wes Hardaker reported there was a problem with validating RRsets that had ownernames with capitals. The fix depends on a fix in Net::DNS::RR that is available in version 0.53_03 or later of the Net::DNS distribution. FEAT: Propper dealing with mnemonics for algorithm and digest type added to DS FIX/FEAT: Mnemonics were written as RSA/MD5 and RSA/SHA1. This has been corrected tp RSASHA1 and RSAMD5, as in the IANA registry. 0.12_02 June 6, 2005 (beta 2 release for 0.13) Bug: new_from_hash would not correctly create the RR since internally typebm is used to store the data this has been fixed so that the following works Net::DNS::RR->new(name=>$name, ttl=>$ttl, type=>"NSEC", nxtdname=>$nxtdname, typelist=>join(" ",@types) ); FEAT: Introduced the "use bytes" pragma to force character interpretation of all the scalars. Any utf processing by perl makes the code behave unpredictable. 0.12_01 April 18, 2005. (beta release for version 0.13) FEAT (!!!): Changed the symantics of the Net::DNS::Keyset::verify method. Read the perldoc for details. The requirement that each key in a keyset has to be selfsigned has been loosened. FEAT: Added a "carp" to the new methods of the NXT RR. Warning that that record is depricated. FEAT: Cleaned the tests so that RRSIG and DNSKEY are used except for SIG0 based tests. FEAT: Changed the name of the siginceptation[SIC] to siginception. Thanks Jakob Schlyter for notifying me of this mistyping. An alias for the method remains available. FEAT: Renamed unset_sep() to clear_sep(). NOTE: To avoid confusion the Net::DNS::SIG::Private class has been removed. Use Net::DNS::SEC::Private! DOC: Added references to RFC 4033, RFC 4034 and RFC 4035. Rewrote parts of the perlpod. 0.12 June 2004 "DNSSEC-bis Release" FEAT: Added utility function key_difference() to Net::DNS::SEC. See perlpod for details. I needed this in other software and figured they are generic enough to make them available through this module. FEAT: Modified some functions to use DNSKEY and RRSIG instead off KEY and SIG. - Net::DNS::Keyset now uses DNSKEY and RRSIG. - the demo function getkeyset.pl now uses DNSKEY too. FEAT: Added the possibility to create a keyset out of two arrays of dnskey and rrsig object. FEAT: Added some helperfunctions to Net::DNS::SEC::Private to read X509 formated private keys and dump them into bind format. This functionality has not been tested well. BUG : When reading a RRSIG from a packet the signame would not have a trailing dot. 0.11_4 Apr 24 2004 Development snapshot. BUG: - Fixed MANIFEST. FEAT: Removed critical dependency on bubblebabble. It is available to DS if installed but not critically dependend. 0.11_3 Mar 4 2004 Development snapshot. BUG: - Fixed minor in signing unknown RR types. 0.11_2 Jan 27 2004 Development snapshot. FEAT: - Prelimanary support for draft-ietf-dnssec-nsec-rdata-02. This depends on support for unknown RR types (Net::DNS version 0.44) 0.11_1 Sep 23 2003 Development snapshot. FEAT: - To be able to deal with argument supplied as either mnemonics or by value the Net::DNS::SEC::argument method was created. It can be used as a class method but it is also inherited by Net::DNS::RR::RRSIG and Net::DNS::RR::DNSKEY. 0.11 August 28 2003 FEAT: - Implemented draft-ietf-dnsext-dnssec-2535typcode-change-04.txt This document has been through review and will be published as standard track RFCs shortly. (Publsished as RFC3755). IMPORTANT: the implementation of the typecode roll deprecated the use of SIG->create for any other reason than SIG0. If you try to create SIGs over RRsets you will be warned. FEAT: - Modified the namespace for the module that holds the name of the private key from Net::DNS::RR::SIG::Private to Net::DNS::SEC::Private. !!!!! Net::DNS::RR::SIG::Private will be deprecated in a next release. !!!!! CLEAN:- Crypt::OpenSSL::RSA v 0.19 introduced the possibility to create keys directly from parameters, although this introduced a dependency on Crypt::OpenSSL::Bignum it allowed to get rid from converting all parameters to DER/ANS1 encoding. Got rid of a number of lines of code. 0.10 January 8 2003 BUG: - Crypt::OpenSSL::RSA::new method has been depricated. Code has been modified to deal with the new constructors 0.09 January 6 2003 FEAT: - Added Net::DNS::RR::SIG::Private. The class provides an abstraction to the private key material. The SIG create method now either takes a filename, like previously, or a Private key object as an argument. If you have to create many signatures the latter is preferred because you only have to read the file with the private key material once. Note that by adding this feature a modification to Net::DNS::Resolver was needed to properly do SIG0. Use Net::DNS version 0.32 or later in combination with this version FEAT: - Wes Griffen added a parameter change to keyset: 'Attached is a diff for Net::DNS::SEC v0.8 that adds a parameter changes keyset->writekeyset($path) to keyset->writekeyset($prefix,$path) where prefix is an optional string that is prepended to the filename of the keyset. That way I can keep my unsigned keyset in keyset-. and have the signed keyset in signed-keyset-.' FEAT: - Babblebubble, handy for telephone confirmation of hashes. Added babblebubble string as comment to DS RR. DS->babble returns the babble bubble string FEAT: - Miek Gieben contributed demo/key2ds 0.08 November 4 2002 BUG: - DSA signature verification failed at random about 1 per 10 sigatures. Corrected allignment problem that lead to this. Added 'stresstest' that loops over creation and verification of signatures to spot these kind of seldomly occuring errors. On my VAIO PII 500Mhz the take about a minute: Files=3, Tests=3056, 69 wallclock secs (63.30 cusr + 0.70 csys = 63.99 CPU) FEAT: - Added Test::More as dependency as on some systems diag was failing. 0.07 October 2 2002 FEAT: - Added demo/make-signed-keyset, a contribution by Wes Griffin. FEAT: - Removed dependency on Math::Pari by porting away from Crypt::DSA to Crypt::OpenSSL::DSA (version 0.10). This should increase portability over platform. T.J. Mather, the Crypt::OpenSSL::DSA maintainer has been particularly helpfull and responsive by adding a few methods to the DSA modules. 0.06 August 16 2002 NOTE: In one of ther versions prior to Net::DNS 0.26 a bug got introduced that made Net::DNS::SEC break. The bug was fixed in version 0.27. BUG: - Check on the existence of the private file improved in SIG.pm - signame got trailing dot with the create methods and not with others. FEAT: - Added privatekeyname method to KEY.pm - Started work on Net::DNS::Keyset. - Added RSA/SHA1 (algorithm ID 5) to SIG.pm. Patch supplied by Andy Vaskys, Network Associates Laboratories. - Rewrote regexp's to not use $' (Postmatch). 0.05 and 0.04 June 17, 2002 BUG: Makefile.PL needed a fix for unused dependency. This failed made the installation fail :-(. 0.04 introduced another failing dependency. DOC: Clarified the documentation at points. 0.03 June 14, 2002 DOC: Few Clarifications 0.02 June 4, 2002 First CPAN Release. Some modifications to the packaging. 0.01 May 25, 2002 Version 0.01 of the package is an alpha for CPAN release. --------------------------------------------------------------------------- The extensions used to be published as a modified version of Net::DNS. The history of those is documented below. 0.20-DNSSEC-0.2: Branched off Net::DNS version 0.20 release (CPAN May 15, 2002) 0.20-DNSSEC-0.1: This version had limited distribution First patch against a version 0.20 snapshot (2002-03-27). http://www.dyndns.org/~ctriv/net-dns-snaps/2002/03/ Modified t/09-dnssec.t; uses Test::More now and includes a number of self consistency checks. DOC Cleaned up the documentation and removed some references to functions and libraries that where not used anyway. FIX 'aesthetic' patch supplied by Simon Josefsson reordering the NXT RR map for the print method. FEAT Added checks on keytype and updated to latest specs for DS Added SIG0 support. See Net::DNS::Packet for details. The verify and create methods of SIG.pm where modified somewhat to cope with the difference. Changed RSA backend from Crypt::RSA to Crypt::OpenSSL::RSA because Crypt::RSA failed during a 'loss of Math::Pari precision in Crypt::Primes'. 0.19-DNSSEC-0.5: BUG DS create method: Hash calculation was done over concattination of name and key material while the hash should be taken over concatenation of canonical name and key rdata. (Fix by Mike Schiraldi) 0.19-DNSSEC-0.4: Added CERT support: Courtesy of Mike Schiraldi for VeriSign BUG Fixed MANIFEST file. make dist will result in proper module tar ball 0.19-DNSSEC-0.3: Solved patch problems that where due to the $Id: Changes 1281 2014-10-24 08:16:24Z willem $ in headers not being from the original distribution. Added DSA signature creation Added DS support You have to uncomment line 77 in Net/DNS.pm to fully enable DS This will assign QTYPE 93 to the DS RR. That value is not assigned by IANA. Added this README.DNSSEC file Added t/09-dnssec.t to the test script with a number of consistency checks. after patching the original distribution direction perl Makefile.PL make test will call this function among other things. BUG KeyID set to 0 for null keys. BUG Sorting of canonical RDATA; Data over which SIG was created was not sorted properly (RFC2535 sect 8.3) causing signature verification errors for RDATA within a RRset having different length (e.g. some NS RRsets would not verify.) 0.19-DNSSEC-0.2: First somewhat public release. --------------------------------------------------------------------------- $Id: Changes 1281 2014-10-24 08:16:24Z willem $ Net-DNS-SEC-0.21/demo/0000755000175100017510000000000012422405450013504 5ustar willemwillemNet-DNS-SEC-0.21/demo/getkeyset.pl0000755000175100017510000000420212422405404016045 0ustar willemwillem#!/usr/bin/perl -sw -I./blib/lib use Net::DNS; use Net::DNS::Keyset; use strict; my $res; my $packet; my $keyset; my $domain=shift; my $nameserver=shift; die "At least one argument needed " if !defined $domain; $res = Net::DNS::Resolver->new; $res->dnssec(1); $res->nameservers($nameserver) if defined $nameserver; $packet = $res->query($domain, 'DNSKEY', 'IN'); die "No results for query $domain DNSKEY" if ! defined $packet; $keyset=Net::DNS::Keyset->new($packet) ; if ( ! $keyset ){ print $Net::DNS::Keyset::keyset_err; return 0; } # Print DS records to STD out # my @ds=$keyset->extract_ds; foreach my $ds ( @ds ) { $ds->print; } # write keyset in current dir. # $keyset->writekeyset; 1; __END__ =head1 NAME getkeyset.pl - DS extraction demo =head1 SYNOPSIS getkeyset.pl [auth_nameserver] =head1 DESCRIPTION The program queries for the key-set of 'domain'. Spits out the DS records and writes the keyset to the current directory. If the second argument is specified the query is performed to that nameserver. =head1 TODO This is only a demonstration program to show how the interface can be used. =head1 COPYRIGHT Copyright (c) 2002 RIPE NCC. Author Olaf M. Kolkman All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. =cut Net-DNS-SEC-0.21/demo/make-signed-keyset0000644000175100017510000000554212422405404017122 0ustar willemwillem#!/usr/bin/perl # # takes a bind public key file and creates a self-signed keyset # use Getopt::Std; use Net::DNS; use File::Basename; # global variables $VERSION = "0.1"; $verbose = 0; $printds = 0; $progname = basename($0); chomp($progname); # main program getopts('dvhVf:n:'); if (defined($opt_d)) { $printds = 1; } if (defined($opt_v)) { $verbose = 1; } if (defined($opt_h)) { &usage(); } if (defined($opt_V)) { &version(); } if ($#ARGV < 0) { &usage(); } # silent some compiler warnings until i figure them out $opt_d=0; $opt_v=0; $opt_h=0; $opt_V=0; &make_keyset(@ARGV); exit(0); # print the usage and exit sub usage { print("usage: $progname [-vhV] file\n"); print("Options:\n"); print(" -d Print the DS record for each key in the keyset.\n"); print(" -v Be verbose.\n"); print(" -h Print this usage message.\n"); print(" -V Print version information.\n"); print(" file BIND public key file.\n"); exit(0); } # print version information sub version { print("$progname v$VERSION using Net::DNS v", Net::DNS->version, "\n"); exit(0); } sub make_keyset { my $file = shift(); my $directory = dirname($file); print("Processing file: $file\n"); if ($verbose) { print("Opening $file\n"); } open(FILE, $file) or die("$progname: unable to open $file.\n"); if ($verbose) { print("Reading $file\n"); } my $keyrr_txt; while () { if (m/^\$.*/) { if ($verbose) { print("Discarding BIND keyword in $file\n"); } next; } $keyrr_txt = $keyrr_txt . $_; } if ($verbose) { print("Creating DNSKEY RR\n"); } my $keyrr = Net::DNS::RR->new($keyrr_txt); if ($verbose) { print("Creating Keyset\n"); } my @keys = ($keyrr); use Net::DNS::Keyset; my $keyset = Net::DNS::Keyset->new(\@keys, "$directory") or die("$progname: unable to create keyset. $Net::DNS::Keyset::keyset_err.\n"); if ($verbose) { print("Verifying Keyset\n"); } $keyset->verify() or die("$progname: unable to verify keyset. $Net::DNS::Keyset::keyset_err.\n"); if ($verbose) { print("Keyset:\n"); $keyset->print(); print("Writing Keyset\n"); } $keyset->writekeyset("signed-") or die("$progname: unable to write keyset. $Net::DNS::Keyset::keyset_err.\n"); if ($printds) { if ($verbose) { print("Extracting DS RR\n"); } my @ds=$keyset->extract_ds(); foreach $ds (@ds) { $ds->print(); } } } =head1 NAME make-signed-keyset - create a self-signed keyset =head1 SYNOPSIS make-signed-keyset [-v] file =head1 DESCRIPTION make-signed-keyset is a program that creates a self-signed keyset from a BIND public key file specified on the command line. The options are as follows: =over =item -v Be verbose. -d Print the DS record for each key in the keyset. =head2 Author Contributed by Wes Griffin =back Net-DNS-SEC-0.21/demo/key2ds0000644000175100017510000000152012422405404014625 0ustar willemwillem#!/usr/bin/perl #$Id: key2ds 999 2012-06-28 09:38:55Z willem $ use strict; use Net::DNS; # A little util to convert DNSKEY records to DS records # From stdin to stdout # # Author: Miek Gieben, NLnetLabs my $key; while (<>) { $key .= $_ }; my $keyrr = new Net::DNS::RR($key); my $dssha256 = Net::DNS::RR::DS->create($keyrr, digtype => "SHA256"); my $dssha1 = create Net::DNS::RR::DS($keyrr, digtype => "SHA1"); print $dssha1->string,"\n"; print $dssha256->string,"\n"; exit 0; =head1 NAME key2ds - Utility to convert a DNSSEC KEY to a DS record =head1 SYNOPSIS C =head1 DESCIPTION C reads the key data from STDIN and print the corresponding DS record on STDOUT. =head1 COPYRIGHT This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 0; Net-DNS-SEC-0.21/META.json0000664000175100017510000000253312422405450014206 0ustar willemwillem{ "abstract" : "DNSSEC extensions to Net::DNS", "author" : [ "Olaf M. Kolkman " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.120351", "license" : [ "mit" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Net-DNS-SEC", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Crypt::OpenSSL::Bignum" : "0.03", "Crypt::OpenSSL::DSA" : "0.1", "Crypt::OpenSSL::RSA" : "0.19", "Crypt::OpenSSL::Random" : "0", "Digest::BubbleBabble" : "0.01", "Digest::SHA" : "5.23", "File::Basename" : "0", "MIME::Base32" : "0", "MIME::Base64" : "0", "Math::BigInt" : "0", "Net::DNS" : "0.69", "Test::More" : "0.47", "Time::Local" : "0", "perl" : "5.006" } } }, "release_status" : "stable", "version" : "0.21" } Net-DNS-SEC-0.21/README0000644000175100017510000001352212422405404013442 0ustar willemwillemNet::DNS::SEC - DNSSEC extensions to Net::DNS ============================================= IMPORTANT UPGRADE NOTE. Please always read the Changes file. It is accessible through: http://search.cpan.org/src/OLAF/Net-DNS-SEC/Changes 1. GENERAL INFO. This module implements DNS Resource Record types that are relevant for DNSSEC operations. This package implements RFC4034 "Resource Records for the DNS Security Extensions" and RFC2931 "DNS Request and Transaction Signatures ( SIG(0)s )" RFC 3225 (Indicating Resolver Support of DNSSEC) support has been integrated into Net::DNS. The extensions provide the following additional features on top of the Net::DNS package (http://www.net-dns.org/). - DS, DNSKEY, RRSIG, NSEC and NSEC3 records. These are all implemented as Net::DNS RR objects. The cryptography has been implemented using Crypt::OpenSSL::DSA, Crypt::OpenSSL::RSA and related modules. The reason for not making these RRs a part of the regular Net::DNS distribution is that they rely on crypto modules that do not easily port. Also see the 'pod' documentation in: Net::DNS::RR::DNSKEY Net::DNS::RR::DS Net::DNS::RR::NSEC Net::DNS::RR::NSEC3 Net::DNS::RR::RRSIG Net::DNS::SEC::Private and for the use of SIG0 see: Net::DNS::Packet (sign_sig0) Net::DNS::RR::KEY Net::DNS::RR::SIG Net::DNS::SEC::Private On top of the RR classes defined above we also provide a class for handling keysets. Keysets are administrative files used by the BIND tools for keymaintenance tasks. Net::DNS::Keyset provides an abstract interface for doing fun things with them. 2. Dependencies This package relies on Net-DNS version 0.69 or higher (also see CHANGES) which has features specifically designed to support Net::DNS::SEC. Among other straightforward routines you will need to have Crypt::OpenSSL::DSA and Crypt::OpenSSL::RSA installed. The package was initially developed on FreeBSD 4.5 with perl5.6.1, as of version 0.11 development and testing where done on MacOS 10.2.6 with perl, v5.8.0 built for darwin. 3. Install Use CPAN. perl -MCPAN -e shell; cpan> install Net::DNS::SEC Alternatively install this package manually: tar -xvzf Net-DNS-SEC-??.tar.gz cd Net-DNS-SEC-??.tar.gz perl Makefile.PL make make test make install 'perl Makefile.PL' will test if all dependencies are in place. 'make test' will do some tests that should all succeed once all dependencies are satisfied. Please report failures during the test phase. 4. Maintenance Please use the CPAN request tracker if you find bugs in the extensions or have DNSSEC feature request. The request tracker is available through: https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Net-DNS-SEC Net::DNS contains a number of hooks for Net::DNS::SEC in the Net::DNS package. If you have problems with Net::DNS in general see: http://www.net-dns.org/ A snapshot of the development code is available through subversion: http://www.net-dns.org/svn/net-dns-sec/trunk Note that the code on the trunk may not be functional. 5. Staying up to date. Announcements about Net::DNS::SEC will be done on http://www.net-dns.net/blog/. An RSS feed is available. 6. Demos demo/getkeyset.pl - is a small demonstration program that will get fetch the keyset for a specified domain, stores them and prints out the DS RRs to STD out. demo/make-signed-keyset - A script contributed by Wes Griffin creates a self-signed keyset from a BIND public key file specified on the command line. demo/key2ds - reads the key data from STDIN and print the corresponding DS record on STDOUT. Contributed by Miek Gieben 7. History The modules in this package have somewhat of a history as a set of patches to the original Net::DNS package. Version 0.02 is the first distribution of the DNSSEC security for CPAN. See the Changes file for more information. 8. Acknowledgements Thanks to the numerous folk that took an interest during development. People that contributed to bug fixes should be acknowledged in the Changes file. If I forgot to mention you there it is not out of bad intention. Thanks to Chris Reinardt for putting the hooks in Net::DNS and suggesting some improvements to the package. Thanks Ian Robertson and T.J. Mather for their support with the Crypt::OpenSSL::[RSA|DSA] modules. 9. Author information Olaf M. Kolkman, RIPE NCC. support: olaf@net-dns.org 10. COPYRIGHT Copyright Notice and Disclaimer Copyright (c) 2001-2005 RIPE NCC. Author Olaf M. Kolkman All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Based on, and contains, code by Copyright (c) 1997-2001 Michael Fuhr. ------------------------------------------------------------------------------ $Id: README 1167 2014-02-03 09:55:08Z willem $ Net-DNS-SEC-0.21/Makefile.PL0000644000175100017510000000355012422405404014534 0ustar willemwillem# # $Id: Makefile.PL 1275 2014-10-14 20:37:29Z willem $ # warn < 'Net::DNS::SEC', VERSION_FROM => 'SEC.pm', ABSTRACT => 'DNSSEC extensions to Net::DNS', AUTHOR => 'Olaf M. Kolkman ', LICENSE => 'mit', MIN_PERL_VERSION => 5.006, PREREQ_PM => { Net::DNS => 0.69, Crypt::OpenSSL::Bignum => 0.03, Crypt::OpenSSL::Random => 0.0, Crypt::OpenSSL::RSA => 0.19, Crypt::OpenSSL::DSA => 0.10, Digest::BubbleBabble => 0.01, Digest::SHA => 5.23, File::Basename => 0.0, Math::BigInt => 0.0, MIME::Base32 => 0.0, MIME::Base64 => 0.0, Time::Local => 0.0, Test::More => 0.47, }, PM => { 'Keyset.pm' => '$(INST_LIBDIR)/Keyset.pm', 'SEC.pm' => '$(INST_LIBDIR)/SEC.pm', 'SEC/Private.pm' => '$(INST_LIBDIR)/SEC/Private.pm', 'RR/DS.pm' => '$(INST_LIBDIR)/RR/DS.pm', 'RR/DLV.pm' => '$(INST_LIBDIR)/RR/DLV.pm', 'RR/KEY.pm' => '$(INST_LIBDIR)/RR/KEY.pm', 'RR/SIG.pm' => '$(INST_LIBDIR)/RR/SIG.pm', 'RR/RRSIG.pm' => '$(INST_LIBDIR)/RR/RRSIG.pm', 'RR/DNSKEY.pm' => '$(INST_LIBDIR)/RR/DNSKEY.pm', 'RR/NSEC.pm' => '$(INST_LIBDIR)/RR/NSEC.pm', 'RR/NSEC3.pm' => '$(INST_LIBDIR)/RR/NSEC3.pm', 'RR/NSEC3PARAM.pm' => '$(INST_LIBDIR)/RR/NSEC3PARAM.pm', }, clean => {FILES => "*~ t/keyset-*"} ); sub MY::libscan { my $path = $_[1]; return '' if $path =~ /\B\.svn\b/; return $path; }