Skip Menu |

This queue is for tickets about the Net-DNS CPAN distribution.

Report information
The Basics
Id: 132772
Status: resolved
Priority: 0/
Queue: Net-DNS

People
Owner: Nobody in particular
Requestors: wolfgang.walter [...] stwm.de
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: 1.24_01



Subject: .key files not handled correctly in TSIG.pm in version 1.24
Date: Sat, 06 Jun 2020 14:16:37 +0200
To: bug-Net-DNS [...] rt.cpan.org
From: Wolfgang Walter <wolfgang.walter [...] stwm.de>
Hello, after upgrading in debian from 1.23 to 1.24 I get the following error: Use of uninitialized value $_[0] in join or string at /usr/share/perl5/Net/DNS/RR/TSIG.pm line 182. when I call sign_tsig() with a .key file. I think the reason is that .key files are now handled as .private file due to the new code in TSIG.pm, line 384: $filename =~ m/^K([^+]+)\+\d+\+\d+\./; # BIND dnssec-keygen my $key = $1; if ( $key && $filename =~ /\.key$/ ) { If it is a .key file, key will usually be undefined and the code path for handling .key files wille therefore not be entered. If I change the condition to if ( ! $key || $filename =~ /\.key$/ ) { sign_tsig() works fine again. Regrads, -- Wolfgang Walter Studentenwerk München Anstalt des öffentlichen Rechts
On Sat Jun 06 08:22:37 2020, wolfgang.walter@stwm.de wrote: Show quoted text
> after upgrading in debian from 1.23 to 1.24 I get the following error: > > Use of uninitialized value $_[0] in join or string at > /usr/share/perl5/Net/DNS/RR/TSIG.pm line 182. > > when I call sign_tsig() with a .key file.
The recommended method of generating TSIG keys changed between 1.23 and 1.24 (see perldoc Net::DNS::RR::TSIG) [Net::DNS 1.23] TSIG keys are symmetric keys generated using dnssec-keygen: $ dnssec-keygen -a HMAC-SHA1 -b 160 -n HOST <keyname> The key will be stored as a private and public keyfile pair K<keyname>+161+<keyid>.private and K<keyname>+161+<keyid>.key dnssec-keygen generates a pair of files, although the secret key is the same in both. The file names depend upon the user specified parameters and the generated key material. The code in 1.23 relies on this convention for private keys but is lax enough to accept any file with .key suffix as a BIND public key. [Net::DNS 1.24] TSIG keys are generated using the tsig-keygen utility distributed with ISC BIND: tsig-keygen -a HMAC-SHA256 host1-host2.example. Observe that tsig-keygen writes the generated key material to STDOUT. tsig-keygen -a HMAC-SHA256 host1-host2.example. >arbitrary.key The user is free to choose the filename which may use the .key suffix. A dnssec-keygen public key is accepted for backward compatibility, but now needs to be distinguishable from "arbitrary.key". Renaming the keyfile breaks ISC BIND's keyfile naming convention. If you wish to use a dnssec-keygen public key with 1.24, then it is important to preserve the original filename. Show quoted text
> If I change the condition to > > if ( ! $key || $filename =~ /\.key$/ ) { > > sign_tsig() works fine again.
This is no solution at all, just moves the point of failure. tsig-keygen key files with .key suffix now fail to parse as a dnssec-keygen public key.
Subject: Re: [rt.cpan.org #132772] .key files not handled correctly in TSIG.pm in version 1.24
Date: Fri, 12 Jun 2020 19:21:01 +0200
To: bug-Net-DNS [...] rt.cpan.org
From: Wolfgang Walter <wolfgang.walter [...] stwm.de>
Am Freitag, 12. Juni 2020, 12:33:45 schrieben Sie: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=132772 > > > On Sat Jun 06 08:22:37 2020, wolfgang.walter@stwm.de wrote:
> > after upgrading in debian from 1.23 to 1.24 I get the following error: > > > > Use of uninitialized value $_[0] in join or string at > > /usr/share/perl5/Net/DNS/RR/TSIG.pm line 182. > > > > when I call sign_tsig() with a .key file.
> > The recommended method of generating TSIG keys changed between 1.23 and 1.24 > (see perldoc Net::DNS::RR::TSIG) > > [Net::DNS 1.23] > > TSIG keys are symmetric keys generated using dnssec-keygen: > > $ dnssec-keygen -a HMAC-SHA1 -b 160 -n HOST <keyname> > > The key will be stored as a private and public keyfile pair > K<keyname>+161+<keyid>.private and K<keyname>+161+<keyid>.key > > > dnssec-keygen generates a pair of files, although the secret key is the same > in both. The file names depend upon the user specified parameters and the > generated key material. > > The code in 1.23 relies on this convention for private keys but is lax > enough to accept any file with .key suffix as a BIND public key. > > > [Net::DNS 1.24] > > TSIG keys are generated using the tsig-keygen utility distributed with > ISC BIND: > > tsig-keygen -a HMAC-SHA256 host1-host2.example. > > > Observe that tsig-keygen writes the generated key material to STDOUT. > > tsig-keygen -a HMAC-SHA256 host1-host2.example. >arbitrary.key >
I know. Show quoted text
> > The user is free to choose the filename which may use the .key suffix. > > A dnssec-keygen public key is accepted for backward compatibility, but now > needs to be distinguishable from "arbitrary.key". Renaming the keyfile > breaks ISC BIND's keyfile naming convention. > > If you wish to use a dnssec-keygen public key with 1.24, then it is > important to preserve the original filename.
> > If I change the condition to > > > > if ( ! $key || $filename =~ /\.key$/ ) { > > > > sign_tsig() works fine again.
> > This is no solution at all, just moves the point of failure. > tsig-keygen key files with .key suffix now fail to parse as a dnssec-keygen > public key.
My problem is that this is a regression, that is: 1.23 and earlier behaved differently and wie rely on it. In 1.23 and earlier a .key file could have an arbitrary name but was always parsed as as dnssec-keyfile. So there was no need to preserve these names. Actually there is no way for me to simple rename this files because our software which uses Net::DNS relies that it can choose the name of the file. I could easily use another ending instead of .key, but I can't go to the K....key scheme. Another solution to keep compabiltiy coudl be to check if $secret is undef and then try to parse as dnssec-keyfile: require File::Spec; # ( keyfile, options ) require Net::DNS::ZoneFile; my $keyfile = new Net::DNS::ZoneFile($karg); my ( $vol, $dir, $filename ) = File::Spec->splitpath( $keyfile->name ); $filename =~ m/^K([^+]+)\+\d+\+\d+\./; # BIND dnssec-keygen my $key = $1; if ( $key && $filename =~ /\.key$/ ) { my $keyrr = $keyfile->read; # BIND dnssec public key croak 'key file incompatible with TSIG' if $keyrr->type ne 'KEY'; return new Net::DNS::RR( name => $keyrr->name, type => 'TSIG', algorithm => $keyrr->algorithm, key => $keyrr->key, @_ ); } my ( $algorithm, $secret, $junk ); while ( $keyfile->_getline ) { $key = $1 if /^key "([^"]+)"/; # BIND tsig key $secret = $1 if /secret "([^"]+)";/; $algorithm = $1 if /algorithm ([^;]+);/; ( $junk, $secret ) = split if /^Key:/; # BIND dnssec private key ( $junk, $algorithm ) = split if /^Algorithm:/; } if (!defined($secret) || !defined($algorithm)) { my $keyrr = $keyfile->read; # BIND dnssec public key croak 'key file incompatible with TSIG' if $keyrr->type ne 'KEY'; return new Net::DNS::RR( name => $keyrr->name, type => 'TSIG', algorithm => $keyrr->algorithm, key => $keyrr->key, @_ ); } return new Net::DNS::RR( name => $key, type => 'TSIG', algorithm => $algorithm, key => $secret, @_ ); } this would probably allow upgrading from 1.23 and earlier to 1.24 and later without breaking code. Regards, -- Wolfgang Walter Studentenwerk München Anstalt des öffentlichen Rechts
On Fri Jun 12 13:21:11 2020, wolfgang.walter@stwm.de wrote: Show quoted text
> My problem is that this is a regression, that is: 1.23 and earlier > behaved differently and wie rely on it.
No! You chose to exploit a laxity in the code when the documentation explicitly tells you the expected filename conventions. Show quoted text
> In 1.23 and earlier a .key file could have an arbitrary name but was > always parsed as as dnssec-keyfile. So there was no need to preserve > these names. Actually there is no way for me to simple rename this > files because our software which uses Net::DNS relies that it can > choose the name of the file. I could easily use another ending instead > of .key, but I can't go to the K....key scheme.
Filename of a BIND public key is and never was a free choice. An obvious solution is to generate your keys using tsig-keygen which allows a free choice of filename and can be read unchanged into your BIND config using $INCLUDE. The alternative is to use a symbolic link: ln -s /path/to/secret/keys/Khmac-sha1.example.+161+39562.key alias.key Show quoted text
> Another solution to keep compabiltiy coudl be to check if $secret is > undef and then try to parse as dnssec-keyfile: > > require File::Spec; # ( keyfile, options ) > require Net::DNS::ZoneFile; > my $keyfile = new Net::DNS::ZoneFile($karg); > ... >8
my ( $algorithm, $secret, $junk ); while ( $keyfile->_getline ) { ### reads entire file ### $key = $1 if /^key "([^"]+)"/; # BIND tsig key $secret = $1 if /secret "([^"]+)";/; $algorithm = $1 if /algorithm ([^;]+);/; ( $junk, $secret ) = split if /^Key:/; # BIND dnssec private key ( $junk, $algorithm ) = split if /^Algorithm:/; } if ( !defined($secret) || !defined($algorithm) ) { my $keyrr = $keyfile->read; ### fails here ### This code does not work because the while loop has already exhausted the file before attempting to read the KEY RR. Show quoted text
> this would probably allow upgrading from 1.23 and earlier to 1.24 and > later without breaking code.
Upgrade from 1.23 to 1.24 already breaks code and no amount of rewriting can change that retrospectively. However, this code does need to be made more robust. Another useful improvement might be to follow symbolic links: ln -s /path/to/secret/keys/Khmac-sha1.example.+161+39562.private private.key ln -s /path/to/secret/keys/Khmac-sha1.example.+161+39562.key public.key This would allow the keyfiles to be distinguishable whilst also being accessed using a more convenient name.
Subject: Re: [rt.cpan.org #132772] .key files not handled correctly in TSIG.pm in version 1.24
Date: Mon, 15 Jun 2020 12:25:50 +0200
To: bug-Net-DNS [...] rt.cpan.org
From: Wolfgang Walter <wolfgang.walter [...] stwm.de>
Am Freitag, 12. Juni 2020, 20:52:41 schrieben Sie: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=132772 > > > On Fri Jun 12 13:21:11 2020, wolfgang.walter@stwm.de wrote:
> > My problem is that this is a regression, that is: 1.23 and earlier > > behaved differently and wie rely on it.
> > No! You chose to exploit a laxity in the code when the documentation > explicitly tells you the expected filename conventions.
> > In 1.23 and earlier a .key file could have an arbitrary name but was > > always parsed as as dnssec-keyfile. So there was no need to preserve > > these names. Actually there is no way for me to simple rename this > > files because our software which uses Net::DNS relies that it can > > choose the name of the file. I could easily use another ending instead > > of .key, but I can't go to the K....key scheme.
> > Filename of a BIND public key is and never was a free choice. >
dnssec-keygen does give you a certain name, thats true. But actually we do not use dnssec-keygen. Show quoted text
> An obvious solution is to generate your keys using tsig-keygen which allows > a free choice of filename and can be read unchanged into your BIND config > using $INCLUDE.
This could be done but will not work with 1.23 an earlier, or I'm missing something?. What wie really do is indeed use tsig-keygen, parse it and then create a .key file because earlier versions of Net::DNS did not parse tsig-keygen generated files. String these keys as a key file (and not as a config-snippet for bind) has other advantaged, too. You can use Net::DNS::ZoneFile to parse them, use database storage schemes for RRs etc. A KEY RR is well defined and can basically be parsed by most DNS libs, whereas a bind conf snippet usually is Show quoted text
> > The alternative is to use a symbolic link: > ln -s /path/to/secret/keys/Khmac-sha1.example.+161+39562.key alias.key >
This would not solve our problem. See below. Show quoted text
> > Another solution to keep compabiltiy coudl be to check if $secret is > > undef and then try to parse as dnssec-keyfile: > > > > require File::Spec; # ( keyfile, options ) > > require Net::DNS::ZoneFile; > > my $keyfile = new Net::DNS::ZoneFile($karg); > > ... > > > >8
> > my ( $algorithm, $secret, $junk ); > while ( $keyfile->_getline ) { ### reads entire file > ### $key = $1 if /^key "([^"]+)"/; # BIND tsig key $secret = $1 > if /secret "([^"]+)";/; > $algorithm = $1 if /algorithm ([^;]+);/; > > ( $junk, $secret ) = split if /^Key:/; # > BIND dnssec private key ( $junk, $algorithm ) = split if /^Algorithm:/; } > > if ( !defined($secret) || !defined($algorithm) ) { > my $keyrr = $keyfile->read; ### fails here ### > > > This code does not work because the while loop has already exhausted the > file before attempting to read the KEY RR.
ok, did not test it. If it is certain to be a file one could use seek(). Show quoted text
> > this would probably allow upgrading from 1.23 and earlier to 1.24 and > > later without breaking code.
> > Upgrade from 1.23 to 1.24 already breaks code and no amount of rewriting can > change that retrospectively. > > However, this code does need to be made more robust. > > Another useful improvement might be to follow symbolic links: > > ln -s /path/to/secret/keys/Khmac-sha1.example.+161+39562.private > private.key ln -s /path/to/secret/keys/Khmac-sha1.example.+161+39562.key > public.key
We have a lot of key files in one directory. Our names consists only of the name of the zone this key should be used for updating that zone (and not the name of the key itself which also contains the nameserver or algo or anything else), so that we can deduct the name of the file directly from the domain we want do update. I probably just change our code to not call sign_tsig() with a filename but with Net::DNS::ZoneFile->new()->read() instead. Regards, -- Wolfgang Walter Studentenwerk München Anstalt des öffentlichen Rechts
On Mon Jun 15 06:26:10 2020, wolfgang.walter@stwm.de wrote: Show quoted text
> > An obvious solution is to generate your keys using tsig-keygen
Show quoted text
> This could be done but will not work with 1.23 an earlier, or I'm > missing something?.
You are missing the rationale for the move to tsig-keygen. TSIG identifies the algorithm by name. The HMAC algorithm codes used in KEY RR were assigned unilaterally by ISC for the purpose of stretching dnssec-keygen to generate TSIG keys. These code assignments were never blessed by IANA or documented anywhere. Key generation for any new algorithm will only be supported by tsig-keygen, without assigning a corresponding algorithm number to use in a KEY RR. In the TSIG context, BIND dnssec-keygen has no future and this KEY RR use case will die with it.
1.24_01 should accept arbitrary filenames, although with a warning to remind you that the "BIND public key" was not generated by dnssec-keygen. The name check is performed on the destination of a symbolic link, which will allow you to hide the ugly name from the rest of your software.
Resolved in Net::DNS 1.25