22 Commits

Author SHA1 Message Date
David Blacka
fb689c046f Update changelog, set this as a release. 2017-01-06 13:01:05 -05:00
David Blacka
8d3746fc22 Validate the the RRset TTL is <= the OrigTTL. 2017-01-06 12:54:16 -05:00
David Blacka
444601fb2a Detect duplicate RRSIGs as well. 2017-01-06 12:53:57 -05:00
David Blacka
c5896495c7 Either R or S could end up being shorter than the expected length, so adjust for that. 2017-01-05 13:50:48 -05:00
David Blacka
c13d9379b3 Update version, convert readme to markdown. 2016-12-09 17:57:09 -05:00
David Blacka
f170bd170a Elliptic curve support.
Improve usage, unknown algorithm error handling in jdnssec-keygen
Use the bouncycastle crypto provider for ECCGOST if available
2016-12-09 17:52:10 -05:00
David Blacka
6bbcf38fe1 update the embedded dnsjava version to 2.1.7 (jdnssec-dnsjava) 2016-08-22 09:40:47 -04:00
David Blacka
15cb5e2ab7 Fix issue in jdnssec-verifyzone (and ZoneVerifier) where junk in the zone wouldn't be handled correctly (that is, ignored.) 2014-04-22 16:39:00 -04:00
David Blacka
9fad4941a6 Make jdnssec-zoneformat -N also compute NSEC3 original owner names for ENTs 2014-04-22 16:37:58 -04:00
David Blacka
18df8a8d9e update version to prep for an official release. 2012-07-16 14:20:14 -04:00
David Blacka
a45f5d1df7 use the perfectly OK (now) TypeMap.toString() method. 2012-07-16 14:16:42 -04:00
David Blacka
3da308c4b9 Fix TypeMap.fromBytes() and add a TypeMap.fromString() method. 2012-07-16 14:16:13 -04:00
David Blacka
efa6dec7f7 update version to prep for an official release. 2012-05-29 13:31:40 -04:00
d3e8c4c913 Add duplicate RR detection to jdnssec-verifyzone, and a command line option to disable it. 2012-05-26 23:14:12 -04:00
b5775a8fdf update README to point to github. 2012-05-26 16:40:50 -04:00
69d965cc0f Wrap the new exceptions to mimic prior behavior. 2012-05-26 16:40:50 -04:00
ca7f10bd07 Instead of using DNSSEC.Secure, DNSSEC.Failed, etc, just use boolean results.
This means we lose the idea of Insecure, but that wasn't effectively being used anyway.
Further, remove any use of the DNSJava Cache class -- that also wasn't being used.
2012-05-26 16:40:50 -04:00
25cc81d46a Replace use of old KEYConverter with new DNSKEYRecord constructor. 2012-05-26 16:40:50 -04:00
2a90a6ccd9 byte -> int for NSEC3 digest type. 2012-05-26 16:40:49 -04:00
b18a96cbfc Change dnsjava algorithm references from DNSSEC.<alg> to DNSSEC.Algorithm.<alg> 2012-05-26 16:40:49 -04:00
cc0873a336 Upgrade local dnsjava fork to 2.3.1-vrsn-1 2012-05-26 16:40:49 -04:00
4d1acb8918 add .gitignore 2012-05-19 20:10:21 -04:00
23 changed files with 1063 additions and 505 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
build
.classpath
.project
jdnssec-tools*.tar.gz
docs

438
ChangeLog
View File

@@ -1,359 +1,419 @@
2017-01-06 David Blacka <davidb@verisign.com>
* Released version 0.13
* ZoneVerifier: detect duplicate RRSIGs as well as other duplicate
RRs.
* DnsSecVerifier: check that the RRset's TTL <= OrigTTL.
2016-12-09 David Blacka <davidb@verisign.com>
* Add key generation, signing, verification support for elliptic
curve algorithms: ECDSA P-256 (13) and ECDSA P-384 (15).
- Opportunistically load the bouncycastle provider for ECCGOST
support.
* DnsKeyAlgorithms: refactoring, new methods to better support
elliptic curve, alias, knowing what algorithms are supported.
* KeyGen: do not display unsupported algorithms.
2016-08-22 David Blacka <davidb@verisign.com>
* Update internal dnsjava to 2.1.7-vrsn-1.
2014-04-22 David Blacka <davidb@verisign.com>
* ZoneFormat: Make -N also compute original ownernames for empty
non-terminal NSEC3 records.
* ZoneVerifier: Improve the zone verifiers handling of "junk" in a
zone (i.e., ignore resource records that aren't actually in the
zone itself.)
2012-07-16 David Blacka <davidb@verisign.com>
* Released version 0.12.
* TypeMap: fix the fromBytes() method, which was incorrect and add
a static fromString() method.
* ProtoNSEC3: use TypeMap's toString method, rather than fetching
the array of types and rendering them directly.
2012-05-29 David Blacka <davidb@verisign.com>
* Released version 0.11.
2012-05-26 David Blacka <davidb@verisign.com>
* Update dnsjava to dnsjava-2.1.3-vrsn-1. Update the code to
adjust for API changes in dnsjava-2.1.x. Highlights:
- no longer use DNSSEC.Failed, DNSSEC.Secure as those constants
are now gone. Instead, any methods returning those constants now
return a boolean, true for DNSSEC.Secure, false for DNSSEC.Failed
or DNSSEC.Insecure.
- No longer use KEYConverter. Instead, uses the new DNSKEYRecord
constructor.
- The NSEC3 digest type is now an int (rather than a byte)
- Algorithm references are now DNSSEC.Algorithm.<alg>
* jdnssec-verifyzone: Add duplicate RR detection (on by default)
and a command line option to disable it.
2011-02-14 David Blacka <davidb@verisign.com>
* Released version 0.10.1.
* Released version 0.10.1.
2011-02-12 David Blacka <davidb@verisign.com>
* Use Java 1.5 generic types when possible. DNSJava itself still
doesn't use them, so we have to suppress warnings when we use
RRset.rrs(), etc.
* Update commons-cli to version 1.2.
* Refactor all of the command line classes. A new command line
base class has been created to eliminate much of the duplicated
code.
* Use Java 1.5 generic types when possible. DNSJava itself still
doesn't use them, so we have to suppress warnings when we use
RRset.rrs(), etc.
* Update commons-cli to version 1.2.
* Refactor all of the command line classes. A new command line
base class has been created to eliminate much of the duplicated
code.
2011-02-09 David Blacka <davidb@verisign.com>
* Enable reading and writing from stdin/stdout for most tools. To
do this, use '-' as the zonefile name.
* jdnssec-signzone, jdnssec-signrrset: remove 'multiline' output
as the default and add a command line switch (-m) to enable it.
That is, these tools will output each RR on a single line by
default, adding -m will restore the prior behavior.
* Enable reading and writing from stdin/stdout for most tools. To
do this, use '-' as the zonefile name.
* jdnssec-signzone, jdnssec-signrrset: remove 'multiline' output
as the default and add a command line switch (-m) to enable it.
That is, these tools will output each RR on a single line by
default, adding -m will restore the prior behavior.
2011-02-08 David Blacka <davidb@verisign.com>
* Minor cleanups to usage statement printing across most of the tools.
* Minor cleanups to usage statement printing across most of the tools.
2011-02-03 David Blacka <davidb@verisign.com>
* Released version 0.10
* jdnssec-keygen: update the default algorithm to 8 (instead of 5).
* Update logging across all command line tools to use a consistent
'-v' option, and consistent, simpler log formatting.
* jdnssec-verifyzone: resume logging the key information at INFO,
but make the default log level WARNING. To see the old logging
behavior, use -v 4.
* Released version 0.10
* jdnssec-keygen: update the default algorithm to 8 (instead of 5).
* Update logging across all command line tools to use a consistent
'-v' option, and consistent, simpler log formatting.
* jdnssec-verifyzone: resume logging the key information at INFO,
but make the default log level WARNING. To see the old logging
behavior, use -v 4.
2011-02-02 David Blacka <davidb@verisign.com>
* DnsKeyConverter: support the new BIND 9.7 private key format,
which only entails recognizing the new version string, since the
new format is a superset of the old format.
* DnsKeyConverter: support the new BIND 9.7 private key format,
which only entails recognizing the new version string, since the
new format is a superset of the old format.
2011-01-11 David Blacka <davidb@verisign.com>
* jdnssec-zoneformat: add a -m option for formatting as
multiline. Add a -N option for determining the original
ownernames for NSEC3 signed zones.
* jdnssec-zoneformat: add a -m option for formatting as
multiline. Add a -N option for determining the original
ownernames for NSEC3 signed zones.
2010-12-14 David Blacka <davidb@verisign.com>
* jdnssec-verifyzone: Add options to either fudge or ignore RRSIG
inception and expiration times.
* jdnssec-verifyzone: Add options to either fudge or ignore RRSIG
inception and expiration times.
2010-12-06 David Blacka <davidb@verisign.com>
* jdnssec-verifyzone: Complete refactored the verification code to
more comprehensively check a zone for DNSSEC validity. Instead of
just verifying signatures, it will also check to see if the NSEC
or NSEC3 chains are valid.
* jdnssec-verifyzone: Complete refactored the verification code to
more comprehensively check a zone for DNSSEC validity. Instead of
just verifying signatures, it will also check to see if the NSEC
or NSEC3 chains are valid.
2010-12-05 David Blacka <davidb@verisign.com>
* jdnssec-signzone: Fix a bug that would incorrectly handle
delgations below delegations (those should be ignored.)
* jdnssec-signzone: Fix a bug that would incorrectly handle
delgations below delegations (those should be ignored.)
* jdnssec-signzone: Make the signer ignore junk below a DNAME.
This differs from BIND's dnssec-signzone behavior (currently), but
is the correct behavior, as stuff below a DNAME doesn't actually
exist in DNS. Note that if a name in a zone has both a DNAME and
a NS RRset (and is not at the apex), then the behavior is a bit
undefined.
* jdnssec-signzone: Make the signer ignore junk below a DNAME.
This differs from BIND's dnssec-signzone behavior (currently), but
is the correct behavior, as stuff below a DNAME doesn't actually
exist in DNS. Note that if a name in a zone has both a DNAME and
a NS RRset (and is not at the apex), then the behavior is a bit
undefined.
* jdnssec-signzone: Fix a bug that would incorrectly set the RRSIG
bit for NSEC3 RRs corresponding to insecure delegations.
* jdnssec-signzone: Fix a bug that would incorrectly set the RRSIG
bit for NSEC3 RRs corresponding to insecure delegations.
* jdnssec-signzone: add a "verbose signing" option. This will
cause the pre-signed bytes and the raw signature bytes to be
output when signing.
* Other fixes: some minor tweaks and comment fixes.
Unfortunately, also a lot of rewrapping and whitespace changes due
to Eclipse. Sigh.
* jdnssec-signzone: add a "verbose signing" option. This will
cause the pre-signed bytes and the raw signature bytes to be
output when signing.
* Other fixes: some minor tweaks and comment fixes.
Unfortunately, also a lot of rewrapping and whitespace changes due
to Eclipse. Sigh.
2010-01-14 David Blacka <davidb@verisign.com>
* Released version 0.9.6
* Released version 0.9.6
2010-01-09 David Blacka <davidb@verisign.com>
* Upgrade to DNSJava 2.0.8 (plus a few local changes). 2.0.8
fixes a major bug in typemap wire conversion.
* Upgrade to DNSJava 2.0.8 (plus a few local changes). 2.0.8
fixes a major bug in typemap wire conversion.
2009-11-02 David Blacka <davidb@verisign.com>
* Released version 0.9.5
* Released version 0.9.5
2009-11-01 David Blacka <davidb@verisign.com>
* Upgrade to DNSJava 2.0.7 (plus a few local changes).
* DnsKeyAlogorithm: change the RSASHA512 number to 10.
* Upgrade to DNSJava 2.0.7 (plus a few local changes).
* DnsKeyAlogorithm: change the RSASHA512 number to 10.
2009-08-23 David Blacka <davidb@verisign.com>
* Released version 0.9.4
* Released version 0.9.4
2009-07-15 David Blacka <davidb@verisign.com>
* SignUtils: Fix major issue where the code that generates that
canonical RRset given signature data wasn't obeying the "Orig TTL"
and "Labels" fields. This is a major issue with verification,
although it doesn't affect signature generation.
* SignUtils: Fix major issue where the code that generates that
canonical RRset given signature data wasn't obeying the "Orig TTL"
and "Labels" fields. This is a major issue with verification,
although it doesn't affect signature generation.
* VerifyZone: Fix bug where the whole-zone security status was
still wrong: unsigned RRsets shouldn't make the zone Bogus.
* VerifyZone: Fix bug where the whole-zone security status was
still wrong: unsigned RRsets shouldn't make the zone Bogus.
2009-06-12 David Blacka <davidb@verisign.com>
* VerifyZone: Fix bug in verification logic so that RRsets that
never find a valid signature (i.e., only have signatures by keys
that aren't in the zone) are considered Bogus. Note that
VerifyZone still can't tell if a RRset that should be signed
wasn't (or vice versa).
* VerifyZone: Fix bug in verification logic so that RRsets that
never find a valid signature (i.e., only have signatures by keys
that aren't in the zone) are considered Bogus. Note that
VerifyZone still can't tell if a RRset that should be signed
wasn't (or vice versa).
* dnsjava: Update local copy of dnsjava library. This version
adds NSEC3 agorithms to DNSSECVerifier and KEYConverter, emulates
DiG's "OPT PSEUDOSECTION" formatting in Message.toString(), and
adds a minimal DHCIDRecord type. Note that the DNSjava trunk has
a different (although functional similar) version of this type.
* dnsjava: Update local copy of dnsjava library. This version
adds NSEC3 agorithms to DNSSECVerifier and KEYConverter, emulates
DiG's "OPT PSEUDOSECTION" formatting in Message.toString(), and
adds a minimal DHCIDRecord type. Note that the DNSjava trunk has
a different (although functional similar) version of this type.
2009-06-09 David Blacka <davidb@verisign.com>
* VerifyZone: Improve the output.
* VerifyZone: Improve the output.
* SignKeyset: Add a command line tool for just signing DNSKEY RRsets.
* SignKeyset: Add a command line tool for just signing DNSKEY RRsets.
2009-02-10 David Blacka <davidb@verisign.com>
* Released version 0.9.0
* Released version 0.9.0
2009-02-08 David Blacka <davidb@verisign.com>
* KeyGen: make RSA large exponent the default. Make it possible
to select small exponent.
* KeyGen: make RSA large exponent the default. Make it possible
to select small exponent.
* KeyInfoTool: add more info to the output, handle multiple files
on the command line.
* KeyInfoTool: add more info to the output, handle multiple files
on the command line.
* DnsKeyAlgorithm: use DNSjava constants, BIND 9.6 mnemonics for
NSEC3 key aliases.
* DnsKeyAlgorithm: use DNSjava constants, BIND 9.6 mnemonics for
NSEC3 key aliases.
2009-02-07 David Blacka <davidb@verisign.com>
* SignZone: add argument for setting the TTL of the NSEC3PARAM
record. This is so we can match current dnssec-signzone
(9.6.0-p1) behavior of using a TTL of zero.
* SignZone: add argument for setting the TTL of the NSEC3PARAM
record. This is so we can match current dnssec-signzone
(9.6.0-p1) behavior of using a TTL of zero.
* Update dnsjava to 2.0.6-vrsn-2, commons-cli to 1.1
* Update dnsjava to 2.0.6-vrsn-2, commons-cli to 1.1
* SignUtils: fix bug where NSEC3 algorithm and flags were transposed.
* SignUtils: fix bug where NSEC3 algorithm and flags were transposed.
* SignUtils: Make sure to use the SOA minimum value for NSEC TTLs,
instead of the ttl of the "node".
* SignUtils: Make sure to use the SOA minimum value for NSEC TTLs,
instead of the ttl of the "node".
2009-02-04 David Blacka <davidb@verisign.com>
* update to dnsjava-2.0.1-vrsn-4 (updated typecodes for
NSEC3/NSEC3PARAM).
* update to dnsjava-2.0.1-vrsn-4 (updated typecodes for
NSEC3/NSEC3PARAM).
* SignUtils: use JDK-native SHA-256 code instead of broken
contributed implementation.
* SignUtils: use JDK-native SHA-256 code instead of broken
contributed implementation.
* DnsKeyAlgorithm: Add RSASHA256 and RSASHA512 algorithm, guessing
at the code points. Note, these require Java 5 or later, or an
alternate crypto provider.
* DnsKeyAlgorithm: Add RSASHA256 and RSASHA512 algorithm, guessing
at the code points. Note, these require Java 5 or later, or an
alternate crypto provider.
* ZoneUtils: add a method to find specific RRs in a list of RRs
or RRsets.
* ZoneUtils: add a method to find specific RRs in a list of RRs
or RRsets.
* SignZone: make jdnssec-signzone a bit more aggressive in finding
keys. Now it will look for keyfiles matching keys at the zone
apex, and, failing that, just look for keyfiles named after the
zone. Specifying any keys at all on the command line will
override this behavior.
* SignZone: make jdnssec-signzone a bit more aggressive in finding
keys. Now it will look for keyfiles matching keys at the zone
apex, and, failing that, just look for keyfiles named after the
zone. Specifying any keys at all on the command line will
override this behavior.
2009-02-01 David Blacka <davidb@verisign.com>
* DnsKeyAlgorithm: add official aliases from RFC 5155.
* DnsKeyAlgorithm: add official aliases from RFC 5155.
* JCEDnsSecSigner: refactor zone signing methods to remove
duplicate code.
* JCEDnsSecSigner: refactor zone signing methods to remove
duplicate code.
* SignZone: move the signZone() methods to JCEDnsSecSigner
* SignZone: move the signZone() methods to JCEDnsSecSigner
* BINDKeyUtils: close the private key file after reading it.
Patch by Wolfgang Nagele.
* BINDKeyUtils: close the private key file after reading it.
Patch by Wolfgang Nagele.
2006-12-15 David Blacka <davidb@verisignlabs.com>
* Release version 0.8.4
* Release version 0.8.4
* SignZone: updated internals (and dnsjava lib) to match wire
format changes introduced by the nsec3-08 draft.
* SignZone: updated internals (and dnsjava lib) to match wire
format changes introduced by the nsec3-08 draft.
2006-10-10 David Blacka <davidb@verisignlabs.com>
* Released version 0.8.3
* Released version 0.8.3
* ZoneFormat: fix RRSIG ordering issue when dealing with multiple
RRSIGs for a given RRset.
* ZoneFormat: fix RRSIG ordering issue when dealing with multiple
RRSIGs for a given RRset.
* ZoneFormat: lowercase all names in the zone.
* ZoneFormat: lowercase all names in the zone.
* Fix packaging errors.
* Fix packaging errors.
2006-09-12 David Blacka <davidb@verisignlabs.com>
* Released version 0.8.0.
* Released version 0.8.0.
2006-09-10 David Blacka <davidb@fury.blacka.com>
* Added the "KeyInfoTool" command line tool as the start of a tool
for decoding DNSKEY information. Right now, mostly just useful
for checking the public exponenent of RSA keys.
* Added the "KeyInfoTool" command line tool as the start of a tool
for decoding DNSKEY information. Right now, mostly just useful
for checking the public exponenent of RSA keys.
* Added the "-e" option to jdnssec-keygen, to instruct the key
generator to use the (common) large exponent in RSA key
generation.
* Added the "-e" option to jdnssec-keygen, to instruct the key
generator to use the (common) large exponent in RSA key
generation.
2006-08-31 David Blacka <davidb@fury.blacka.com>
* Modified jdnssec-signzone to set the ttls of NSEC3 records (so
far) to the SOA minimum value.
* Modified jdnssec-signzone to set the ttls of NSEC3 records (so
far) to the SOA minimum value.
* Add NSEC3PARAM support for compatibility with the -07 NSEC3
draft.
* Add NSEC3PARAM support for compatibility with the -07 NSEC3
draft.
2006-05-24 David Blacka <davidb@verisignlabs.com>
* Add some error checking for the NSEC3 command line parameters
for jdnssec-signzone.
* Add some error checking for the NSEC3 command line parameters
for jdnssec-signzone.
* Update local dnsjava build to 2.0.1. This also contains a
change to the NSEC3 rdata format (as per the -06pre NSEC3 draft).
The change is the addition of a "next hashed owner name" length
octet.
* Update local dnsjava build to 2.0.1. This also contains a
change to the NSEC3 rdata format (as per the -06pre NSEC3 draft).
The change is the addition of a "next hashed owner name" length
octet.
* Modified the jdnssec-* shell wrappers to also use the local
build area version of the jdnssec-tools.jar file. This allows the
standard jdnssec-* wrappers to work right from the build area.
* Modified the jdnssec-* shell wrappers to also use the local
build area version of the jdnssec-tools.jar file. This allows the
standard jdnssec-* wrappers to work right from the build area.
* Add support of the SHA256 algorithm for DS records. This uses
the SHA256 class that I obtained from Scott Rose (thanks Scott!).
* Add support of the SHA256 algorithm for DS records. This uses
the SHA256 class that I obtained from Scott Rose (thanks Scott!).
* Change the name of the package and jar file to jdnssec-tools
(from java-dnssec-tools) for consistency.
* Change the name of the package and jar file to jdnssec-tools
(from java-dnssec-tools) for consistency.
* release version 0.7.0.
* release version 0.7.0.
2006-05-23 David Blacka <davidb@verisignlabs.com>
* Add support for algorithm aliases. This feature is so that the
user can declare the DNSKEY algorithm x is the same as algorithm 5
(e.g.). So far, this only works with straight integer algorithm
identifiers (no private alg support yet).
* Add support for algorithm aliases. This feature is so that the
user can declare the DNSKEY algorithm x is the same as algorithm 5
(e.g.). So far, this only works with straight integer algorithm
identifiers (no private alg support yet).
* Fix jdnssec-signzone so that you can specify multiple KSKs on
the command line. Apparently, commons-cli actually does handle
repeating command line options correctly.
* Fix jdnssec-signzone so that you can specify multiple KSKs on
the command line. Apparently, commons-cli actually does handle
repeating command line options correctly.
2006-05-03 David Blacka <davidb@verisignlabs.com>
* Add preliminary implementation of jdnssec-dstool. This is a
simple command line tool that takes a DNSKEY record and converts
it into a DS record (or a DLV record). Right now, it requires
that the key is stored in a file ending with '.key'.
* Add preliminary implementation of jdnssec-dstool. This is a
simple command line tool that takes a DNSKEY record and converts
it into a DS record (or a DLV record). Right now, it requires
that the key is stored in a file ending with '.key'.
* release version 0.6.0.
* release version 0.6.0.
2006-03-15 David Blacka <davidb@verisignlabs.com>
* Type map changes for NSEC3, corresponding to changes in draft
-05pre. Essentially: NSEC3 and RRSIG bits are not set for most
(all) NSEC3 records any longer.
* Type map changes for NSEC3, corresponding to changes in draft
-05pre. Essentially: NSEC3 and RRSIG bits are not set for most
(all) NSEC3 records any longer.
2006-03-06 David Blacka <davidb@verisignlabs.com>
* release version 0.5.0.
* release version 0.5.0.
2006-02-16 David Blacka <davidb@verisignlabs.com>
* Make RecordComparator also compare RDATA so the removeDuplicates
step actually works reliabled. This was masked by the dupicate
suppression in org.xbill.DNS.RRset.
* Make RecordComparator also compare RDATA so the removeDuplicates
step actually works reliabled. This was masked by the dupicate
suppression in org.xbill.DNS.RRset.
* Only allow one command line specified KSK since commons-cli
doesn't seem to handle multi-arg options correctly.
* Only allow one command line specified KSK since commons-cli
doesn't seem to handle multi-arg options correctly.
* Do not croak on the lack of the command-line keys for now.
* Do not croak on the lack of the command-line keys for now.
* New version of local dnsjava build containing NSEC3 changes
corresponding to the -04pre draft.
* New version of local dnsjava build containing NSEC3 changes
corresponding to the -04pre draft.
2005-11-16 David Blacka <davidb@verisignlabs.com>
* Make jdnssec-verifyzone work with just the zone (which is
self-signed anyway).
* Make jdnssec-verifyzone work with just the zone (which is
self-signed anyway).
* release version 0.4.2.
* release version 0.4.2.
2005-11-09 David Blacka <davidb@verisignlabs.com>
* Add original ownername comments to the NSEC3 generation.
* Add original ownername comments to the NSEC3 generation.
2005-11-08 David Blacka <davidb@verisignlabs.com>
* New zone formatter.
* New zone formatter.
* Misc bug fixes.
* Misc bug fixes.
* release version 0.4.1.
* release version 0.4.1.
2005-11-07 David Blacka <davidb@verisignlabs.com>
* Update the local dnsjava build with a bugfix.
* Update the local dnsjava build with a bugfix.
* Fix ordering problem with ProtoNSEC3s.
* Fix ordering problem with ProtoNSEC3s.
2005-11-06 David Blacka <davidb@verisignlabs.com>
* Actually use the --iterations command line option of
jdnssec-signzone.
* Actually use the --iterations command line option of
jdnssec-signzone.
2005-10-27 David Blacka <davidb@verisignlabs.com>
* Add NSEC3 support for jdnssec-signzone.
* Add NSEC3 support for jdnssec-signzone.
* Remove support for plain Opt-In (until private algorithms work).
* Remove support for plain Opt-In (until private algorithms work).
* release version 0.4.0.
* release version 0.4.0.
2005-08-14 David Blacka <davidb@verisignlabs.com>
* Move the signZone function into the SignZone class (from the
SignUtils) class.
* Move the signZone function into the SignZone class (from the
SignUtils) class.
* General cleanup.
* General cleanup.
* Add local _jdnssec-* shell wrappers. These use build/classes in
the classpath so can be used to run the tools right out of the
build area.
* Add local _jdnssec-* shell wrappers. These use build/classes in
the classpath so can be used to run the tools right out of the
build area.
2005-08-13 David Blacka <davidb@verisignlabs.com>
* Update to DNSjava 2.0.0
* Update to DNSjava 2.0.0
* Refactor command line parsing.
* Refactor command line parsing.
* Switch to using java.util.logging for logging.
* Switch to using java.util.logging for logging.

62
README
View File

@@ -1,62 +0,0 @@
jdnssec-tools
http://www.verisignlabs.com/jdnssec-tools/
Author: David Blacka (davidb@verisign.com)
This is a collection of DNSSEC tools written in Java. They are
intended to be an addition or replacement for the DNSSEC tools that
are part of BIND 9.
These tools depend upon DNSjava (http://www.xbill.org/dnsjava), the
Jakarta Commons CLI and Logging libraries (http://jakarta.apache.org),
and Sun's Java Cryptography extensions. A copy of each of these
libraries is included in the distribution. Currently, these tools use
a custom version of the DNSjava library (for NSEC3 support), which is
provided.
See the "licenses" directory for the licensing information of this
package and the other packages that are distributed with it.
Getting started:
1. Unpack the binary distribution:
% tar zxvf java-dnssec-tools-x.x.x.tar.gz
2. Run the various tools from their unpacked location:
% cd java-dnssec-tools-x.x.x
% ./bin/jdnssec-signzone -h
Building from source:
1. Unpack the source distribution, preferably into the same directory
that the binary distribution was unpacked.
% tar zxvf java-dnssec-tools-x.x.x-src.tar.gz
2. Edit the build.properties file to suit your environment.
3. Run Ant (see http://ant.apache.org for information about the Ant
build tool).
% ant
4. You can build the distribution tarballs with 'ant dist'. You can
run the tools directly from the build area (without building the
jdnssec-tools.jar file) by using the ./bin/_jdnssec_* wrappers.
The source for this project is available in subversion, at
http://svn.verisignlabs.com/jdnssec/tools/trunk. Source for
the modified DNSjava library can be found in subversion at
http://svn.verisignlabs.com/jdnssec/dnsjava/trunk.
---
Questions or comments may be directed to the author
(mailto:davidb@verisign.com) or sent to the
dnssec@verisignlabs.com mailing list
(https://lists.verisignlabs.com/mailman/listinfo/dnssec).

46
README.md Normal file
View File

@@ -0,0 +1,46 @@
# jdnssec-tools
* http://www.verisignlabs.com/jdnssec-tools/
* https://github.com/dblacka/jdnssec-tools/wiki
Author: David Blacka (davidb@verisign.com)
This is a collection of DNSSEC tools written in Java. They are intended to be an addition or replacement for the DNSSEC tools that are part of BIND 9.
These tools depend upon DNSjava (http://www.xbill.org/dnsjava), the Jakarta Commons CLI and Logging libraries (https://commons.apache.org/proper/commons-cli), and Sun's Java Cryptography extensions. A copy of each of these libraries is included in the distribution. Currently, these tools use a custom version of the DNSjava library with minor modifications, which is provided.
See the "licenses" directory for the licensing information of this package and the other packages that are distributed with it.
Getting started:
1. Unpack the binary distribution:
tar zxvf java-dnssec-tools-x.x.x.tar.gz
2. Run the various tools from their unpacked location:
cd java-dnssec-tools-x.x.x
./bin/jdnssec-signzone -h
Building from source:
1. Unpack the source distribution, preferably into the same directory that the binary distribution was unpacked.
tar zxvf java-dnssec-tools-x.x.x-src.tar.gz
2. Edit the build.properties file to suit your environment.
3. Run Ant (see http://ant.apache.org for information about the Ant build tool).
ant
4. You can build the distribution tarballs with 'ant dist'. You can run the tools directly from the build area (without building the jdnssec-tools.jar file) by using the ./bin/_jdnssec_* wrappers.
The source for this project is available in git on github: https://github.com/dblacka/jdnssec-tools
Source for the modified DNSjava library can be found on github as well: https://github.com/dblacka/jdnssec-dnsjava
---
Questions or comments may be directed to the author (mailto:davidb@verisign.com) or sent to the dnssec@verisignlabs.com mailing list (https://lists.verisignlabs.com/mailman/listinfo/dnssec).

View File

@@ -1 +1 @@
version=0.10.1
version=0.13

View File

@@ -44,8 +44,6 @@
<javac srcdir="${build.src}"
destdir="${build.dest}"
classpathref="project.classpath"
source="1.5"
target="1.5"
deprecation="true"
includeantruntime="false"
includes="com/verisignlabs/dnssec/" />
@@ -70,7 +68,7 @@
verbose="true" author="true"
windowtitle="jdnssec-tools-${version}"
use="true">
<link href="http://java.sun.com/j2se/1.4.2/docs/api/" />
<link href="https://docs.oracle.com/javase/8/docs/api/" />
<link href="http://www.xbill.org/dnsjava/doc/" />
</javadoc>
</target>
@@ -172,4 +170,3 @@
</target>
</project>

Binary file not shown.

Binary file not shown.

View File

@@ -74,17 +74,18 @@ public class KeyGen extends CLBase
OptionBuilder.withDescription("ZONE | OTHER (default ZONE)");
opts.addOption(OptionBuilder.create('n'));
String[] algStrings = DnsKeyAlgorithm.getInstance().supportedAlgMnemonics();
OptionBuilder.hasArg();
OptionBuilder.withArgName("algorithm");
OptionBuilder.withDescription("RSA | RSASHA1 | RSAMD5 | DH | DSA "
+ "| RSA-NSEC3-SHA1 | DSA-NSEC3-SHA1 "
+ "| RSASHA256 | RSASHA512 | alias, RSASHA1 is default.");
OptionBuilder.withDescription(String.join(" | ", algStrings) +
" | alias, RSASHA256 is default.");
opts.addOption(OptionBuilder.create('a'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("size");
OptionBuilder.withDescription("key size, in bits. (default = 1024)\n"
+ "RSA: [512..4096]\n" + "DSA: [512..1024]\n" + "DH: [128..4096]");
OptionBuilder.withDescription("key size, in bits. default is 1024. "
+ "RSA: [512..4096], DSA: [512..1024], DH: [128..4096], "
+ "ECDSA: ignored");
opts.addOption(OptionBuilder.create('b'));
OptionBuilder.hasArg();
@@ -98,7 +99,6 @@ public class KeyGen extends CLBase
OptionBuilder.withArgName("dir");
OptionBuilder.withDescription("place generated key files in this " + "directory");
opts.addOption(OptionBuilder.create('d'));
opts.addOption(OptionBuilder.create('A'));
}
protected void processOptions(CommandLine cli)
@@ -136,6 +136,11 @@ public class KeyGen extends CLBase
if ((optstr = cli.getOptionValue('a')) != null)
{
algorithm = parseAlg(optstr);
if (algorithm < 0)
{
System.err.println("DNSSEC algorithm " + optstr + " is not supported");
usage();
}
}
if ((optstr = cli.getOptionValue('b')) != null)
@@ -166,7 +171,11 @@ public class KeyGen extends CLBase
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
int alg = parseInt(s, -1);
if (alg > 0) return alg;
if (alg > 0)
{
if (algs.supportedAlgorithm(alg)) return alg;
return -1;
}
return algs.stringToAlgorithm(s);
}

View File

@@ -28,7 +28,6 @@ import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRSIGRecord;
import org.xbill.DNS.RRset;
@@ -186,11 +185,11 @@ public class SignKeyset extends CLBase
// skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue;
int result = verifier.verify(rrset, null);
boolean result = verifier.verify(rrset);
if (result != DNSSEC.Secure)
if (!result)
{
log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset);
log.fine("Signatures did not verify for RRset: " + rrset);
secure = false;
}
}

View File

@@ -28,7 +28,6 @@ import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRSIGRecord;
import org.xbill.DNS.RRset;
@@ -185,11 +184,11 @@ public class SignRRset extends CLBase
// skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue;
int result = verifier.verify(rrset, null);
boolean result = verifier.verify(rrset);
if (result != DNSSEC.Secure)
if (!result)
{
log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset);
log.fine("Signatures did not verify for RRset: " + rrset);
secure = false;
}
}

View File

@@ -34,7 +34,6 @@ import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.DSRecord;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRset;
@@ -343,11 +342,11 @@ public class SignZone extends CLBase
// skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue;
int result = verifier.verify(rrset, null);
boolean result = verifier.verify(rrset);
if (result != DNSSEC.Secure)
if (!result)
{
log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset);
log.fine("Signatures did not verify for RRset: " + rrset);
secure = false;
}
}
@@ -547,6 +546,7 @@ public class SignZone extends CLBase
}
}
br.close();
if (res.size() == 0) return null;
return res;
}

View File

@@ -48,6 +48,7 @@ public class VerifyZone extends CLBase
public int startfudge = 0;
public int expirefudge = 0;
public boolean ignoreTime = false;
public boolean ignoreDups = false;
public CLIState()
{
@@ -71,6 +72,10 @@ public class VerifyZone extends CLBase
OptionBuilder.withLongOpt("ignore-time");
OptionBuilder.withDescription("Ignore RRSIG inception and expiration time errors.");
opts.addOption(OptionBuilder.create());
OptionBuilder.withLongOpt("ignore-duplicate-rrs");
OptionBuilder.withDescription("Ignore duplicate record errors.");
opts.addOption(OptionBuilder.create());
}
protected void processOptions(CommandLine cli)
@@ -80,6 +85,11 @@ public class VerifyZone extends CLBase
ignoreTime = true;
}
if (cli.hasOption("ignore-duplicate-rrs"))
{
ignoreDups = true;
}
String optstr = null;
if ((optstr = cli.getOptionValue('S')) != null)
{
@@ -126,6 +136,7 @@ public class VerifyZone extends CLBase
zoneverifier.getVerifier().setStartFudge(state.startfudge);
zoneverifier.getVerifier().setExpireFudge(state.expirefudge);
zoneverifier.getVerifier().setIgnoreTime(state.ignoreTime);
zoneverifier.setIgnoreDuplicateRRs(state.ignoreDups);
List<Record> records = ZoneUtils.readZoneFile(state.zonefile, null);

View File

@@ -126,13 +126,20 @@ public class ZoneFormat extends CLBase
Collections.sort(zone, new RecordComparator());
// first, find the NSEC3PARAM record -- this is an inefficient linear
// search.
// search, although it should be near the head of the list.
NSEC3PARAMRecord nsec3param = null;
HashMap<String, String> map = new HashMap<String, String>();
base32 b32 = new base32(base32.Alphabet.BASE32HEX, false, true);
Name zonename = null;
for (Record r : zone)
{
if (r.getType() == Type.SOA)
{
zonename = r.getName();
continue;
}
if (r.getType() == Type.NSEC3PARAM)
{
nsec3param = (NSEC3PARAMRecord) r;
@@ -140,6 +147,8 @@ public class ZoneFormat extends CLBase
}
}
// If we couldn't determine a zone name, we have an issue.
if (zonename == null) return;
// If there wasn't one, we have nothing to do.
if (nsec3param == null) return;
@@ -150,10 +159,23 @@ public class ZoneFormat extends CLBase
if (r.getName().equals(last_name)) continue;
if (r.getType() == Type.NSEC3) continue;
byte[] hash = nsec3param.hashName(r.getName());
Name n = r.getName();
byte[] hash = nsec3param.hashName(n);
String hashname = b32.toString(hash);
map.put(hashname, r.getName().toString().toLowerCase());
last_name = r.getName();
map.put(hashname, n.toString().toLowerCase());
last_name = n;
// inefficiently create hashes for the possible ancestor ENTs
for (int i = zonename.labels() + 1; i < n.labels(); ++i)
{
Name parent = new Name(n, n.labels() - i);
byte[] parent_hash = nsec3param.hashName(parent);
String parent_hashname = b32.toString(parent_hash);
if (!map.containsKey(parent_hashname))
{
map.put(parent_hashname, parent.toString().toLowerCase());
}
}
}
// Final pass, assign the names if we can

View File

@@ -29,13 +29,12 @@
package com.verisignlabs.dnssec.security;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.spec.RSAKeyGenParameterSpec;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
import java.util.logging.Logger;
import org.xbill.DNS.DNSSEC;
@@ -56,20 +55,38 @@ import org.xbill.DNS.DNSSEC;
public class DnsKeyAlgorithm
{
public static final int UNKNOWN = -1;
public static final int RSA = 1;
public static final int DH = 2;
public static final int DSA = 3;
// Our base algorithm numbers. This is a normalization of the DNSSEC
// algorithms (which are really signature algorithms). Thus RSASHA1,
// RSASHA256, etc. all boil down to 'RSA' here.
public static final int UNKNOWN = -1;
public static final int RSA = 1;
public static final int DH = 2;
public static final int DSA = 3;
public static final int ECC_GOST = 4;
public static final int ECDSA = 5;
private static class Entry
private static class AlgEntry
{
public int dnssecAlgorithm;
public String sigName;
public int baseType;
public Entry(String sigName, int baseType)
public AlgEntry(int algorithm, String sigName, int baseType)
{
this.sigName = sigName;
this.baseType = baseType;
this.dnssecAlgorithm = algorithm;
this.sigName = sigName;
this.baseType = baseType;
}
}
private static class ECAlgEntry extends AlgEntry
{
public ECParameterSpec ec_spec;
public ECAlgEntry(int algorithm, String sigName, int baseType, ECParameterSpec spec)
{
super(algorithm, sigName, baseType);
this.ec_spec = spec;
}
}
@@ -77,7 +94,7 @@ public class DnsKeyAlgorithm
* This is a mapping of algorithm identifier to Entry. The Entry contains the
* data needed to map the algorithm to the various crypto implementations.
*/
private HashMap<Integer, Entry> mAlgorithmMap;
private HashMap<Integer, AlgEntry> mAlgorithmMap;
/**
* This is a mapping of algorithm mnemonics to algorithm identifiers.
*/
@@ -90,58 +107,112 @@ public class DnsKeyAlgorithm
/** This is a cached key pair generator for RSA keys. */
private KeyPairGenerator mRSAKeyGenerator;
/** This is a cache key pair generator for DSA keys. */
/** This is a cached key pair generator for DSA keys. */
private KeyPairGenerator mDSAKeyGenerator;
/** This is a cached key pair generator for ECC GOST keys. */
private KeyPairGenerator mECGOSTKeyGenerator;
/** This is a cached key pair generator for ECDSA_P256 keys. */
private KeyPairGenerator mECKeyGenerator;
private Logger log = Logger.getLogger(this.getClass().toString());
private Logger log = Logger.getLogger(this.getClass().toString());
/** This is the global instance for this class. */
private static DnsKeyAlgorithm mInstance = null;
public DnsKeyAlgorithm()
{
mAlgorithmMap = new HashMap<Integer, Entry>();
// Attempt to add the bouncycastle provider.
// This is so we can use this provider if it is available, but not require
// the user to add it as one of the java.security providers.
try
{
Class<?> bc_provider_class = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
Provider bc_provider = (Provider) bc_provider_class.newInstance();
Security.addProvider(bc_provider);
}
catch (ReflectiveOperationException e) { }
initialize();
}
private void initialize()
{
mAlgorithmMap = new HashMap<Integer, AlgEntry>();
mMnemonicToIdMap = new HashMap<String, Integer>();
mIdToMnemonicMap = new HashMap<Integer, String>();
// Load the standard DNSSEC algorithms.
addAlgorithm(DNSSEC.RSAMD5, new Entry("MD5withRSA", RSA));
addMnemonic("RSAMD5", DNSSEC.RSAMD5);
addAlgorithm(DNSSEC.Algorithm.RSAMD5, "MD5withRSA", RSA);
addMnemonic("RSAMD5", DNSSEC.Algorithm.RSAMD5);
addAlgorithm(DNSSEC.DH, new Entry("", DH));
addMnemonic("DH", DNSSEC.DH);
addAlgorithm(DNSSEC.Algorithm.DH, "", DH);
addMnemonic("DH", DNSSEC.Algorithm.DH);
addAlgorithm(DNSSEC.DSA, new Entry("SHA1withDSA", DSA));
addMnemonic("DSA", DNSSEC.DSA);
addAlgorithm(DNSSEC.Algorithm.DSA, "SHA1withDSA", DSA);
addMnemonic("DSA", DNSSEC.Algorithm.DSA);
addAlgorithm(DNSSEC.RSASHA1, new Entry("SHA1withRSA", RSA));
addMnemonic("RSASHA1", DNSSEC.RSASHA1);
addMnemonic("RSA", DNSSEC.RSASHA1);
addAlgorithm(DNSSEC.Algorithm.RSASHA1, "SHA1withRSA", RSA);
addMnemonic("RSASHA1", DNSSEC.Algorithm.RSASHA1);
addMnemonic("RSA", DNSSEC.Algorithm.RSASHA1);
// Load the (now) standard aliases
addAlias(DNSSEC.DSA_NSEC3_SHA1, "DSA-NSEC3-SHA1", DNSSEC.DSA);
addAlias(DNSSEC.RSA_NSEC3_SHA1, "RSA-NSEC3-SHA1", DNSSEC.RSASHA1);
addAlias(DNSSEC.Algorithm.DSA_NSEC3_SHA1, "DSA-NSEC3-SHA1", DNSSEC.Algorithm.DSA);
addAlias(DNSSEC.Algorithm.RSA_NSEC3_SHA1, "RSA-NSEC3-SHA1", DNSSEC.Algorithm.RSASHA1);
// Also recognize the BIND 9.6 mnemonics
addMnemonic("NSEC3DSA", DNSSEC.DSA_NSEC3_SHA1);
addMnemonic("NSEC3RSASHA1", DNSSEC.RSA_NSEC3_SHA1);
addMnemonic("NSEC3DSA", DNSSEC.Algorithm.DSA_NSEC3_SHA1);
addMnemonic("NSEC3RSASHA1", DNSSEC.Algorithm.RSA_NSEC3_SHA1);
// Algorithms added by RFC 5702.
// NOTE: these algorithms aren't available in Java 1.4's sunprovider
// implementation (but are in java 1.5's and later).
addAlgorithm(8, new Entry("SHA256withRSA", RSA));
addMnemonic("RSASHA256", 8);
addAlgorithm(DNSSEC.Algorithm.RSASHA256, "SHA256withRSA", RSA);
addMnemonic("RSASHA256", DNSSEC.Algorithm.RSASHA256);
addAlgorithm(10, new Entry("SHA512withRSA", RSA));
addMnemonic("RSASHA512", 10);
addAlgorithm(DNSSEC.Algorithm.RSASHA512, "SHA512withRSA", RSA);
addMnemonic("RSASHA512", DNSSEC.Algorithm.RSASHA512);
// ECC-GOST is not supported by Java 1.8's Sun crypto provider. The
// bouncycastle.org provider, however, does.
// GostR3410-2001-CryptoPro-A is the named curve in the BC provider, but we
// will get the parameters directly.
addAlgorithm(DNSSEC.Algorithm.ECC_GOST, "GOST3411withECGOST3410", ECC_GOST, null);
addMnemonic("ECCGOST", DNSSEC.Algorithm.ECC_GOST);
addMnemonic("ECC-GOST", DNSSEC.Algorithm.ECC_GOST);
addAlgorithm(DNSSEC.Algorithm.ECDSAP256SHA256, "SHA256withECDSA", ECDSA, "secp256r1");
addMnemonic("ECDSAP256SHA256", DNSSEC.Algorithm.ECDSAP256SHA256);
addMnemonic("ECDSA-P256", DNSSEC.Algorithm.ECDSAP256SHA256);
addAlgorithm(DNSSEC.Algorithm.ECDSAP384SHA384, "SHA384withECDSA", ECDSA, "secp384r1");
addMnemonic("ECDSAP384SHA384", DNSSEC.Algorithm.ECDSAP384SHA384);
addMnemonic("ECDSA-P384", DNSSEC.Algorithm.ECDSAP384SHA384);
}
private void addAlgorithm(int algorithm, Entry entry)
private void addAlgorithm(int algorithm, String sigName, int baseType)
{
mAlgorithmMap.put(algorithm, new AlgEntry(algorithm, sigName, baseType));
}
private void addAlgorithm(int algorithm, String sigName, int baseType, String curveName)
{
ECParameterSpec ec_spec = ECSpecFromAlgorithm(algorithm);
if (ec_spec == null) ec_spec = ECSpecFromName(curveName);
if (ec_spec == null) return;
// Check to see if we can get a Signature object for this algorithm.
try {
Signature.getInstance(sigName);
} catch (NoSuchAlgorithmException e) {
// If not, do not add the algorithm.
return;
}
ECAlgEntry entry = new ECAlgEntry(algorithm, sigName, baseType, ec_spec);
mAlgorithmMap.put(algorithm, entry);
}
private void addMnemonic(String m, int alg)
{
// Do not add mnemonics for algorithms that ended up not actually being supported.
if (!mAlgorithmMap.containsKey(alg)) return;
mMnemonicToIdMap.put(m.toUpperCase(), alg);
if (!mIdToMnemonicMap.containsKey(alg))
{
@@ -172,14 +243,77 @@ public class DnsKeyAlgorithm
}
}
private Entry getEntry(int alg)
private AlgEntry getEntry(int alg)
{
return mAlgorithmMap.get(alg);
}
// For curves where we don't (or can't) get the parameters from a standard
// name, we can construct the parameters here. For now, we only do this for
// the ECC-GOST curve.
private ECParameterSpec ECSpecFromAlgorithm(int algorithm)
{
switch (algorithm)
{
case DNSSEC.Algorithm.ECC_GOST:
{
// From RFC 4357 Section 11.4
BigInteger p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", 16);
BigInteger a = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", 16);
BigInteger b = new BigInteger("A6", 16);
BigInteger gx = new BigInteger("1", 16);
BigInteger gy = new BigInteger("8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14", 16);
BigInteger n = new BigInteger( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", 16);
EllipticCurve curve = new EllipticCurve(new ECFieldFp(p), a, b);
return new ECParameterSpec(curve, new ECPoint(gx, gy), n, 1);
}
default:
return null;
}
}
// Fetch the curve parameters from a named curve.
private ECParameterSpec ECSpecFromName(String stdName)
{
try
{
AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
ECGenParameterSpec ecg_spec = new ECGenParameterSpec(stdName);
ap.init(ecg_spec);
return ap.getParameterSpec(ECParameterSpec.class);
}
catch (NoSuchAlgorithmException e) {
log.info("Elliptic Curve not supported by any crypto provider: " + e.getMessage());
}
catch (InvalidParameterSpecException e) {
log.info("Elliptic Curve " + stdName + " not supported");
}
return null;
}
public String[] supportedAlgMnemonics()
{
Set<Integer> keyset = mAlgorithmMap.keySet();
Integer[] algs = keyset.toArray(new Integer[keyset.size()]);
Arrays.sort(algs);
String[] result = new String[algs.length];
for (int i = 0; i < algs.length; i++)
{
result[i] = mIdToMnemonicMap.get(algs[i]);
}
return result;
}
/**
* Return a Signature object for the specified DNSSEC algorithm.
* @param algorithm The DNSSEC algorithm (by number).
* @return a Signature object.
*/
public Signature getSignature(int algorithm)
{
Entry entry = getEntry(algorithm);
AlgEntry entry = getEntry(algorithm);
if (entry == null) return null;
Signature s = null;
@@ -197,6 +331,62 @@ public class DnsKeyAlgorithm
return s;
}
/**
* Given one of the ECDSA algorithms (ECDSAP256SHA256, etc.) return
* the elliptic curve parameters.
*
* @param algorithm
* The DNSSEC algorithm number.
* @return The calculated JCA ECParameterSpec for that DNSSEC algorithm, or
* null if not a recognized/supported EC algorithm.
*/
public ECParameterSpec getEllipticCurveParams(int algorithm)
{
AlgEntry entry = getEntry(algorithm);
if (entry == null) return null;
if (!(entry instanceof ECAlgEntry)) return null;
ECAlgEntry ec_entry = (ECAlgEntry) entry;
return ec_entry.ec_spec;
}
/**
* Translate a possible algorithm alias back to the original DNSSEC algorithm
* number
*
* @param algorithm
* a DNSSEC algorithm that may be an alias.
* @return -1 if the algorithm isn't recognised, the orignal algorithm number
* if it is.
*/
public int originalAlgorithm(int algorithm)
{
AlgEntry entry = getEntry(algorithm);
if (entry == null) return -1;
return entry.dnssecAlgorithm;
}
/**
* Test if a given algorithm is supported.
*
* @param algorithm The DNSSEC algorithm number.
* @return true if the algorithm is a recognized and supported algorithm or alias.
*/
public boolean supportedAlgorithm(int algorithm)
{
if (mAlgorithmMap.containsKey(algorithm)) return true;
return false;
}
/**
* Given an algorithm mnemonic, convert the mnemonic to a DNSSEC algorithm
* number.
*
* @param s
* The mnemonic string. This is case-insensitive.
* @return -1 if the mnemonic isn't recognized or supported, the algorithm
* number if it is.
*/
public int stringToAlgorithm(String s)
{
Integer alg = mMnemonicToIdMap.get(s.toUpperCase());
@@ -204,6 +394,14 @@ public class DnsKeyAlgorithm
return -1;
}
/**
* Given a DNSSEC algorithm number, return the "preferred" mnemonic.
*
* @param algorithm
* A DNSSEC algorithm number.
* @return The preferred mnemonic string, or null if not supported or
* recognized.
*/
public String algToString(int algorithm)
{
return mIdToMnemonicMap.get(algorithm);
@@ -211,26 +409,11 @@ public class DnsKeyAlgorithm
public int baseType(int algorithm)
{
Entry entry = getEntry(algorithm);
AlgEntry entry = getEntry(algorithm);
if (entry != null) return entry.baseType;
return UNKNOWN;
}
public int standardAlgorithm(int algorithm)
{
switch (baseType(algorithm))
{
case RSA:
return DNSSEC.RSASHA1;
case DSA:
return DNSSEC.DSA;
case DH:
return DNSSEC.DH;
default:
return UNKNOWN;
}
}
public boolean isDSA(int algorithm)
{
return (baseType(algorithm) == DSA);
@@ -243,6 +426,7 @@ public class DnsKeyAlgorithm
switch (baseType(algorithm))
{
case RSA:
{
if (mRSAKeyGenerator == null)
{
mRSAKeyGenerator = KeyPairGenerator.getInstance("RSA");
@@ -270,7 +454,9 @@ public class DnsKeyAlgorithm
pair = mRSAKeyGenerator.generateKeyPair();
break;
}
case DSA:
{
if (mDSAKeyGenerator == null)
{
mDSAKeyGenerator = KeyPairGenerator.getInstance("DSA");
@@ -278,6 +464,49 @@ public class DnsKeyAlgorithm
mDSAKeyGenerator.initialize(keysize);
pair = mDSAKeyGenerator.generateKeyPair();
break;
}
case ECC_GOST:
{
if (mECGOSTKeyGenerator == null)
{
mECGOSTKeyGenerator = KeyPairGenerator.getInstance("ECGOST3410");
}
ECParameterSpec ec_spec = getEllipticCurveParams(algorithm);
try
{
mECGOSTKeyGenerator.initialize(ec_spec);
}
catch (InvalidAlgorithmParameterException e)
{
// Fold the InvalidAlgorithmParameterException into our existing
// thrown exception. Ugly, but requires less code change.
throw new NoSuchAlgorithmException("invalid key parameter spec");
}
pair = mECGOSTKeyGenerator.generateKeyPair();
break;
}
case ECDSA:
{
if (mECKeyGenerator == null)
{
mECKeyGenerator = KeyPairGenerator.getInstance("EC");
}
ECParameterSpec ec_spec = getEllipticCurveParams(algorithm);
try
{
mECKeyGenerator.initialize(ec_spec);
}
catch (InvalidAlgorithmParameterException e)
{
// Fold the InvalidAlgorithmParameterException into our existing
// thrown exception. Ugly, but requires less code change.
throw new NoSuchAlgorithmException("invalid key parameter spec");
}
pair = mECKeyGenerator.generateKeyPair();
break;
}
default:
throw new NoSuchAlgorithmException("Alg " + algorithm);
}

View File

@@ -27,15 +27,8 @@ import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.interfaces.*;
import java.security.spec.*;
import java.util.StringTokenizer;
import javax.crypto.interfaces.DHPrivateKey;
@@ -44,10 +37,9 @@ import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPrivateKeySpec;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.DNSSEC.DNSSECException;
import org.xbill.DNS.Name;
import org.xbill.DNS.Record;
import org.xbill.DNS.Type;
import org.xbill.DNS.security.KEYConverter;
import org.xbill.DNS.utils.base64;
/**
@@ -63,9 +55,12 @@ public class DnsKeyConverter
private KeyFactory mRSAKeyFactory;
private KeyFactory mDSAKeyFactory;
private KeyFactory mDHKeyFactory;
private KeyFactory mECKeyFactory;
private DnsKeyAlgorithm mAlgorithms;
public DnsKeyConverter()
{
mAlgorithms = DnsKeyAlgorithm.getInstance();
}
/**
@@ -78,27 +73,30 @@ public class DnsKeyConverter
{
if (pKeyRecord.getKey() == null) return null;
// For now, instead of re-implementing parseRecord (or adding this stuff
// to DNSjava), we will just translate the algorithm back to a standard
// algorithm. Note that this will unnecessarily convert RSAMD5 to RSASHA1.
// Because we have arbitrarily aliased algorithms, we need to possibly
// translate the aliased algorithm back to the actual algorithm.
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
int standard_alg = algs.standardAlgorithm(pKeyRecord.getAlgorithm());
int originalAlgorithm = mAlgorithms.originalAlgorithm(pKeyRecord.getAlgorithm());
if (standard_alg <= 0)
throw new NoSuchAlgorithmException("DNSKEY algorithm "
+ pKeyRecord.getAlgorithm() + " is unrecognized");
if (originalAlgorithm <= 0) throw new NoSuchAlgorithmException("DNSKEY algorithm "
+ pKeyRecord.getAlgorithm() + " is unrecognized");
if (pKeyRecord.getAlgorithm() != standard_alg)
if (pKeyRecord.getAlgorithm() != originalAlgorithm)
{
pKeyRecord = new DNSKEYRecord(pKeyRecord.getName(),
pKeyRecord.getDClass(),
pKeyRecord = new DNSKEYRecord(pKeyRecord.getName(), pKeyRecord.getDClass(),
pKeyRecord.getTTL(), pKeyRecord.getFlags(),
pKeyRecord.getProtocol(), standard_alg,
pKeyRecord.getProtocol(), originalAlgorithm,
pKeyRecord.getKey());
}
return KEYConverter.parseRecord(pKeyRecord);
try
{
return pKeyRecord.getPublicKey();
}
catch (DNSSECException e)
{
throw new NoSuchAlgorithmException(e);
}
}
/**
@@ -107,10 +105,16 @@ public class DnsKeyConverter
public DNSKEYRecord generateDNSKEYRecord(Name name, int dclass, long ttl,
int flags, int alg, PublicKey key)
{
Record kr = KEYConverter.buildRecord(name, Type.DNSKEY, dclass, ttl, flags,
DNSKEYRecord.Protocol.DNSSEC, alg, key);
return (DNSKEYRecord) kr;
try
{
return new DNSKEYRecord(name, dclass, ttl, flags, DNSKEYRecord.Protocol.DNSSEC, alg,
key);
}
catch (DNSSECException e)
{
// FIXME: this mimics the behavior of KEYConverter.buildRecord(), which would return null if the algorithm was unknown.
return null;
}
}
// Private Key Specific Parsing routines
@@ -121,11 +125,9 @@ public class DnsKeyConverter
public PrivateKey convertEncodedPrivateKey(byte[] key, int algorithm)
{
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key);
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
try
{
switch (algs.baseType(algorithm))
switch (mAlgorithms.baseType(algorithm))
{
case DnsKeyAlgorithm.RSA:
return mRSAKeyFactory.generatePrivate(spec);
@@ -135,12 +137,17 @@ public class DnsKeyConverter
}
catch (GeneralSecurityException e)
{
e.printStackTrace();
}
return null;
}
private int parseInt(String s, int def)
/**
* A simple wrapper for parsing integers; parse failures result in the
* supplied default.
*/
private static int parseInt(String s, int def)
{
try
{
@@ -184,9 +191,8 @@ public class DnsKeyConverter
String[] toks = val.split("\\s", 2);
val = toks[0];
int alg = parseInt(val, -1);
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
switch (algs.baseType(alg))
switch (mAlgorithms.baseType(alg))
{
case DnsKeyAlgorithm.RSA:
return parsePrivateRSA(lines);
@@ -194,6 +200,10 @@ public class DnsKeyConverter
return parsePrivateDSA(lines);
case DnsKeyAlgorithm.DH:
return parsePrivateDH(lines);
case DnsKeyAlgorithm.ECC_GOST:
return parsePrivateECDSA(lines, alg);
case DnsKeyAlgorithm.ECDSA:
return parsePrivateECDSA(lines, alg);
default:
throw new IOException("unsupported private key algorithm: " + val);
}
@@ -205,7 +215,7 @@ public class DnsKeyConverter
/**
* @return the value part of an "attribute:value" pair. The value is trimmed.
*/
private String value(String av)
private static String value(String av)
{
if (av == null) return null;
@@ -423,6 +433,60 @@ public class DnsKeyConverter
}
}
/**
* Given the remaining lines in a BIND9-style ECDSA private key, parse the key
* info and translate it into a JCA private key object.
* @param lines The remaining lines in a private key file (after
* @throws NoSuchAlgorithmException
* If elliptic curve is not available.
*/
private PrivateKey parsePrivateECDSA(StringTokenizer lines, int algorithm)
throws NoSuchAlgorithmException
{
BigInteger s = null;
while (lines.hasMoreTokens())
{
String line = lines.nextToken();
if (line == null) continue;
if (line.startsWith("#")) continue;
String val = value(line);
if (val == null) continue;
byte[] data = base64.fromString(val);
if (line.startsWith("PrivateKey: "))
{
s = new BigInteger(1, data);
}
}
if (mECKeyFactory == null)
{
mECKeyFactory = KeyFactory.getInstance("EC");
}
ECParameterSpec ec_spec = mAlgorithms.getEllipticCurveParams(algorithm);
if (ec_spec == null)
{
throw new NoSuchAlgorithmException("DNSSEC algorithm " + algorithm +
" is not a recognized Elliptic Curve algorithm");
}
KeySpec spec = new ECPrivateKeySpec(s, ec_spec);
try
{
return mECKeyFactory.generatePrivate(spec);
}
catch (InvalidKeySpecException e)
{
e.printStackTrace();
return null;
}
}
/**
* Given a private key and public key, generate the BIND9 style private key
* format.
@@ -441,14 +505,17 @@ public class DnsKeyConverter
{
return generatePrivateDH((DHPrivateKey) priv, (DHPublicKey) pub, alg);
}
else if (priv instanceof ECPrivateKey && pub instanceof ECPublicKey)
{
return generatePrivateEC((ECPrivateKey) priv, (ECPublicKey) pub, alg);
}
return null;
}
/**
* Convert from 'unsigned' big integer to original 'signed format' in Base64
*/
private String b64BigInt(BigInteger i)
private static String b64BigInt(BigInteger i)
{
byte[] orig_bytes = i.toByteArray();
@@ -471,10 +538,9 @@ public class DnsKeyConverter
{
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
out.println("Private-key-format: v1.2");
out.println("Algorithm: " + algorithm + " (" + algs.algToString(algorithm)
out.println("Algorithm: " + algorithm + " (" + mAlgorithms.algToString(algorithm)
+ ")");
out.print("Modulus: ");
out.println(b64BigInt(key.getModulus()));
@@ -502,12 +568,11 @@ public class DnsKeyConverter
{
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
DHParameterSpec p = key.getParams();
out.println("Private-key-format: v1.2");
out.println("Algorithm: " + algorithm + " (" + algs.algToString(algorithm)
out.println("Algorithm: " + algorithm + " (" + mAlgorithms.algToString(algorithm)
+ ")");
out.print("Prime(p): ");
out.println(b64BigInt(p.getP()));
@@ -527,12 +592,11 @@ public class DnsKeyConverter
{
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
DSAParams p = key.getParams();
out.println("Private-key-format: v1.2");
out.println("Algorithm: " + algorithm + " (" + algs.algToString(algorithm)
out.println("Algorithm: " + algorithm + " (" + mAlgorithms.algToString(algorithm)
+ ")");
out.print("Prime(p): ");
out.println(b64BigInt(p.getP()));
@@ -547,4 +611,23 @@ public class DnsKeyConverter
return sw.toString();
}
/**
* Given an elliptic curve key pair, and the actual algorithm (which will
* describe the curve used), return the BIND9-style text encoding.
*/
private String generatePrivateEC(ECPrivateKey priv, ECPublicKey pub, int alg)
{
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
out.println("Private-key-format: v1.2");
out.println("Algorithm: " + alg + " (" + mAlgorithms.algToString(alg)
+ ")");
out.print("PrivateKey: ");
out.println(b64BigInt(priv.getS()));
return sw.toString();
}
}

View File

@@ -333,15 +333,15 @@ public class DnsKeyPair
if (pk != null)
{
// currently, alg 5 is the default over alg 1 (RSASHA1).
if (pk instanceof RSAPublicKey) return DNSSEC.RSASHA1;
if (pk instanceof DSAPublicKey) return DNSSEC.DSA;
if (pk instanceof RSAPublicKey) return DNSSEC.Algorithm.RSASHA1;
if (pk instanceof DSAPublicKey) return DNSSEC.Algorithm.DSA;
}
PrivateKey priv = getPrivate();
if (priv != null)
{
if (priv instanceof RSAPrivateKey) return DNSSEC.RSASHA1;
if (priv instanceof DSAPrivateKey) return DNSSEC.DSA;
if (priv instanceof RSAPrivateKey) return DNSSEC.Algorithm.RSASHA1;
if (priv instanceof DSAPrivateKey) return DNSSEC.Algorithm.DSA;
}
return -1;

View File

@@ -43,7 +43,7 @@ import org.xbill.DNS.*;
* @author $Author$
* @version $Revision$
*/
public class DnsSecVerifier implements Verifier
public class DnsSecVerifier
{
private class TrustedKeyStore
@@ -157,47 +157,19 @@ public class DnsSecVerifier implements Verifier
mIgnoreTime = v;
}
@SuppressWarnings("unchecked")
private DnsKeyPair findCachedKey(Cache cache, Name name, int algorithm, int footprint)
private DnsKeyPair findKey(Name name, int algorithm, int footprint)
{
RRset[] keysets = cache.findAnyRecords(name, Type.KEY);
if (keysets == null) return null;
// look for the particular key
// FIXME: this assumes that name+alg+footprint is unique.
for (Iterator<Record> i = keysets[0].rrs(); i.hasNext();)
{
Record r = i.next();
if (r.getType() != Type.DNSKEY) continue;
DNSKEYRecord keyrec = (DNSKEYRecord) r;
if (keyrec.getAlgorithm() == algorithm && keyrec.getFootprint() == footprint)
{
return new DnsKeyPair(keyrec, (PrivateKey) null);
}
}
return null;
return mKeyStore.find(name, algorithm, footprint);
}
private DnsKeyPair findKey(Cache cache, Name name, int algorithm, int footprint)
private boolean validateSignature(RRset rrset, RRSIGRecord sigrec, List<String> reasons)
{
DnsKeyPair pair = mKeyStore.find(name, algorithm, footprint);
if (pair == null && cache != null)
{
pair = findCachedKey(cache, name, algorithm, footprint);
}
return pair;
}
private byte validateSignature(RRset rrset, RRSIGRecord sigrec, List<String> reasons)
{
if (rrset == null || sigrec == null) return DNSSEC.Failed;
if (rrset == null || sigrec == null) return false;
if (!rrset.getName().equals(sigrec.getName()))
{
log.fine("Signature name does not match RRset name");
if (reasons != null) reasons.add("Signature name does not match RRset name");
return DNSSEC.Failed;
return false;
}
if (rrset.getType() != sigrec.getTypeCovered())
{
@@ -205,7 +177,7 @@ public class DnsSecVerifier implements Verifier
if (reasons != null) reasons.add("Signature type does not match RRset type");
}
if (mIgnoreTime) return DNSSEC.Secure;
if (mIgnoreTime) return true;
Date now = new Date();
Date start = sigrec.getTimeSigned();
@@ -221,7 +193,7 @@ public class DnsSecVerifier implements Verifier
{
log.fine("Signature is not yet valid");
if (reasons != null) reasons.add("Signature not yet valid");
return DNSSEC.Failed;
return false;
}
}
@@ -235,39 +207,44 @@ public class DnsSecVerifier implements Verifier
{
log.fine("Signature has expired (now = " + now + ", sig expires = " + expire);
if (reasons != null) reasons.add("Signature has expired.");
return DNSSEC.Failed;
return false;
}
}
return DNSSEC.Secure;
if (rrset.getTTL() > sigrec.getOrigTTL())
{
log.fine("RRset's TTL is greater than the Signature's orignal TTL");
if (reasons != null) reasons.add("RRset TTL greater than RRSIG origTTL");
return false;
}
return true;
}
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache)
public boolean verifySignature(RRset rrset, RRSIGRecord sigrec)
{
return verifySignature(rrset, sigrec, cache, null);
return verifySignature(rrset, sigrec, null);
}
/**
* Verify an RRset against a particular signature.
*
* @return DNSSEC.Secure if the signature verified, DNSSEC.Failed if it did
* not verify (for any reason), and DNSSEC.Insecure if verification
* could not be completed (usually because the public key was not
* available).
* @return true if the signature verified, false if it did
* not verify (for any reason, including not finding the DNSKEY.)
*/
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache, List<String> reasons)
public boolean verifySignature(RRset rrset, RRSIGRecord sigrec, List<String> reasons)
{
byte result = validateSignature(rrset, sigrec, reasons);
if (result != DNSSEC.Secure) return result;
boolean result = validateSignature(rrset, sigrec, reasons);
if (!result) return result;
DnsKeyPair keypair = findKey(cache, sigrec.getSigner(), sigrec.getAlgorithm(),
DnsKeyPair keypair = findKey(sigrec.getSigner(), sigrec.getAlgorithm(),
sigrec.getFootprint());
if (keypair == null)
{
if (reasons != null) reasons.add("Could not find matching trusted key");
log.fine("could not find matching trusted key");
return DNSSEC.Insecure;
return false;
}
try
@@ -286,14 +263,20 @@ public class DnsSecVerifier implements Verifier
sig = SignUtils.convertDSASignature(sig);
}
if (sigrec.getAlgorithm() == DNSSEC.Algorithm.ECDSAP256SHA256 ||
sigrec.getAlgorithm() == DNSSEC.Algorithm.ECDSAP384SHA384)
{
sig = SignUtils.convertECDSASignature(sig);
}
if (!signer.verify(sig))
{
if (reasons != null) reasons.add("Signature failed to verify cryptographically");
log.fine("Signature failed to verify cryptographically");
return DNSSEC.Failed;
return false;
}
return DNSSEC.Secure;
return true;
}
catch (IOException e)
{
@@ -305,39 +288,37 @@ public class DnsSecVerifier implements Verifier
}
if (reasons != null) reasons.add("Signature failed to verify due to exception");
log.fine("Signature failed to verify due to exception");
return DNSSEC.Insecure;
return false;
}
/**
* Verifies an RRset. This routine does not modify the RRset.
*
* @return DNSSEC.Secure if the set verified, DNSSEC.Failed if it did not, and
* DNSSEC.Insecure if verification could not complete.
* @return true if the set verified, false if it did not.
*/
@SuppressWarnings("unchecked")
public int verify(RRset rrset, Cache cache)
public boolean verify(RRset rrset)
{
int result = mVerifyAllSigs ? DNSSEC.Secure : DNSSEC.Insecure;
boolean result = mVerifyAllSigs ? true : false;
Iterator i = rrset.sigs();
if (!i.hasNext())
{
log.fine("RRset failed to verify due to lack of signatures");
return DNSSEC.Insecure;
return false;
}
while (i.hasNext())
{
RRSIGRecord sigrec = (RRSIGRecord) i.next();
byte res = verifySignature(rrset, sigrec, cache);
boolean res = verifySignature(rrset, sigrec);
if (!mVerifyAllSigs && res == DNSSEC.Secure) return res;
// If not requiring all signature to validate, then any successful validation is sufficient.
if (!mVerifyAllSigs && res) return res;
if (!mVerifyAllSigs && res < result) result = res;
if (mVerifyAllSigs && res != DNSSEC.Secure && res < result)
// Otherwise, note if a signature failed to validate.
if (mVerifyAllSigs && !res)
{
result = res;
}

View File

@@ -33,12 +33,7 @@ import java.util.List;
import java.util.ListIterator;
import java.util.logging.Logger;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRSIGRecord;
import org.xbill.DNS.RRset;
import org.xbill.DNS.Record;
import org.xbill.DNS.Type;
import org.xbill.DNS.*;
import org.xbill.DNS.utils.hexdump;
/**
@@ -58,7 +53,7 @@ public class JCEDnsSecSigner
private DnsKeyConverter mKeyConverter;
private boolean mVerboseSigning = false;
private Logger log;
private Logger log = Logger.getLogger(this.getClass().toString());
public JCEDnsSecSigner()
{
@@ -197,6 +192,12 @@ public class JCEDnsSecSigner
DSAPublicKey pk = (DSAPublicKey) pair.getPublic();
sig = SignUtils.convertDSASignature(pk.getParams(), sig);
}
// Convert to RFC 6605, etc format
if (pair.getDNSKEYAlgorithm() == DNSSEC.Algorithm.ECDSAP256SHA256 ||
pair.getDNSKEYAlgorithm() == DNSSEC.Algorithm.ECDSAP384SHA384)
{
sig = SignUtils.convertECDSASignature(pair.getDNSKEYAlgorithm(), sig);
}
RRSIGRecord sigrec = SignUtils.generateRRSIG(sig, presig);
if (mVerboseSigning)
{

View File

@@ -45,7 +45,7 @@ import org.xbill.DNS.utils.base32;
public class ProtoNSEC3
{
private Name originalOwner;
private byte hashAlg;
private int hashAlg;
private byte flags;
private int iterations;
private byte[] salt;
@@ -63,7 +63,7 @@ public class ProtoNSEC3
* Creates an NSEC3 Record from the given data.
*/
public ProtoNSEC3(byte[] owner, Name originalOwner, Name zone, int dclass, long ttl,
byte hashAlg, byte flags, int iterations, byte[] salt, byte[] next,
int hashAlg, byte flags, int iterations, byte[] salt, byte[] next,
TypeMap typemap)
{
this.zone = zone;
@@ -80,7 +80,7 @@ public class ProtoNSEC3
}
public ProtoNSEC3(byte[] owner, Name originalOwner, Name zone, int dclass, long ttl,
byte hashAlg, byte flags, int iterations, byte[] salt, byte[] next,
int hashAlg, byte flags, int iterations, byte[] salt, byte[] next,
int[] types)
{
this(owner, originalOwner, zone, dclass, ttl, hashAlg, flags, iterations, salt, next,
@@ -168,7 +168,7 @@ public class ProtoNSEC3
return dclass;
}
public byte getHashAlgorithm()
public int getHashAlgorithm()
{
return hashAlg;
}
@@ -242,14 +242,8 @@ public class ProtoNSEC3
sb.append(' ');
String nextstr = (next == null) ? "(null)" : b32.toString(next);
sb.append(nextstr);
int[] types = getTypes();
for (int i = 0; i < types.length; i++)
{
sb.append(" ");
sb.append(Type.string(types[i]));
}
if (originalOwner != null) sb.append(" ; " + originalOwner);
sb.append(' ');
sb.append(typemap.toString());
return sb.toString();
}

View File

@@ -429,6 +429,128 @@ public class SignUtils
return sig;
}
// Given one of the ECDSA algorithms determine the "length", which is the
// length, in bytes, of both 'r' and 's' in the ECDSA signature.
private static int ecdsaLength(int algorithm) throws SignatureException
{
switch (algorithm)
{
case DNSSEC.Algorithm.ECDSAP256SHA256: return 32;
case DNSSEC.Algorithm.ECDSAP384SHA384: return 48;
default:
throw new SignatureException("Algorithm " + algorithm +
" is not a supported ECDSA signature algorithm.");
}
}
/**
* Convert a JCE standard ECDSA signature (which is a ASN.1 encoding) into a
* standard DNS signature.
*
* The format of the ASN.1 signature is
*
* ASN1_SEQ . seq_length . ASN1_INT . r_length . R . ANS1_INT . s_length . S
*
* where R and S may have a leading zero byte if without it the values would
* be negative.
*
* The format of the DNSSEC signature is just R . S where R and S are both
* exactly "length" bytes.
*
* @param signature
* The output of a ECDSA signature object.
* @return signature data formatted for use in DNSSEC.
* @throws SignatureException if the ASN.1 encoding appears to be corrupt.
*/
public static byte[] convertECDSASignature(int algorithm, byte[] signature)
throws SignatureException
{
int exp_length = ecdsaLength(algorithm);
byte[] sig = new byte[exp_length * 2];
if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT)
{
throw new SignatureException("Invalid ASN.1 signature format: expected SEQ, INT");
}
int r_len = signature[3];
int r_pos = 4;
if (signature[r_pos + r_len] != ASN1_INT)
{
throw new SignatureException("Invalid ASN.1 signature format: expected SEQ, INT, INT");
}
int s_pos = r_pos + r_len + 2;
int s_len = signature[r_pos + r_len + 1];
// Adjust for leading zeros on both R and S
if (signature[r_pos] == 0) {
r_pos++;
r_len--;
}
if (signature[s_pos] == 0) {
s_pos++;
s_len--;
}
System.arraycopy(signature, r_pos, sig, 0 + (exp_length - r_len), r_len);
System.arraycopy(signature, s_pos, sig, exp_length + (exp_length - s_len), s_len);
return sig;
}
/**
* Convert a DNS standard ECDSA signature (defined in RFC 6605) into a
* JCE standard ECDSA signature, which is encoded in ASN.1.
*
* The format of the ASN.1 signature is
*
* ASN1_SEQ . seq_length . ASN1_INT . r_length . R . ANS1_INT . s_length . S
*
* where R and S may have a leading zero byte if without it the values would
* be negative.
*
* The format of the DNSSEC signature is just R . S where R and S are both
* exactly "length" bytes.
*
* @param signature
* The binary signature data from an RRSIG record.
* @return signature data that may be used in a JCE Signature object for
* verification purposes.
*/
public static byte[] convertECDSASignature(byte[] signature)
{
byte r_src_pos, r_src_len, r_pad, s_src_pos, s_src_len, s_pad, len;
r_src_len = s_src_len = (byte) (signature.length / 2);
r_src_pos = 0; r_pad = 0;
s_src_pos = (byte) (r_src_pos + r_src_len); s_pad = 0;
len = (byte) (6 + r_src_len + s_src_len);
if (signature[r_src_pos] < 0) {
r_pad = 1; len++;
}
if (signature[s_src_pos] < 0) {
s_pad = 1; len++;
}
byte[] sig = new byte[len];
byte pos = 0;
sig[pos++] = ASN1_SEQ;
sig[pos++] = (byte) (len - 2);
sig[pos++] = ASN1_INT;
sig[pos++] = (byte) (r_src_len + r_pad);
pos += r_pad;
System.arraycopy(signature, r_src_pos, sig, pos, r_src_len);
pos += r_src_len;
sig[pos++] = ASN1_INT;
sig[pos++] = (byte) (s_src_len + s_pad);
pos += s_pad;
System.arraycopy(signature, s_src_pos, sig, pos, s_src_len);
return sig;
}
/**
* This is a convenience routine to help us classify records/RRsets.
*
@@ -1430,7 +1552,7 @@ public class SignUtils
* @throws NoSuchAlgorithmException
* If the hash algorithm is unrecognized.
*/
public static byte[] nsec3hash(Name n, byte hash_algorithm, int iterations, byte[] salt)
public static byte[] nsec3hash(Name n, int hash_algorithm, int iterations, byte[] salt)
throws NoSuchAlgorithmException
{
MessageDigest md;

View File

@@ -21,6 +21,7 @@ import org.xbill.DNS.Type;
public class TypeMap
{
private static final Integer[] integerArray = new Integer[0];
private static final byte[] emptyBitmap = new byte[0];
private Set<Integer> typeSet;
@@ -47,6 +48,9 @@ public class TypeMap
return typeSet.contains(type);
}
/**
* Given an array of DNS type code, construct a TypeMap object.
*/
public static TypeMap fromTypes(int[] types)
{
TypeMap m = new TypeMap();
@@ -68,12 +72,12 @@ public class TypeMap
int m = 0;
TypeMap typemap = new TypeMap();
int map_number;
int page;
int byte_length;
while (m < map.length)
{
map_number = map[m++];
page = map[m++];
byte_length = map[m++];
for (int i = 0; i < byte_length; i++)
@@ -82,7 +86,7 @@ public class TypeMap
{
if ((map[m + i] & (1 << (7 - j))) != 0)
{
typemap.set(map_number * 8 + j);
typemap.set((page << 8) + (i * 8) + j);
}
}
}
@@ -92,6 +96,21 @@ public class TypeMap
return typemap;
}
/**
* Given list of type mnemonics, construct a TypeMap object.
*/
public static TypeMap fromString(String types)
{
TypeMap typemap = new TypeMap();
for (String type : types.split("\\s+"))
{
typemap.set(Type.value(type));
}
return typemap;
}
/** @return the normal string representation of the typemap. */
public String toString()
{
@@ -102,7 +121,7 @@ public class TypeMap
for (int i = 0; i < types.length; i++)
{
sb.append(" ");
if (i > 0) sb.append(" ");
sb.append(Type.string(types[i]));
}
@@ -140,6 +159,8 @@ public class TypeMap
{
int[] types = getTypes();
if (types.length == 0) return emptyBitmap;
Arrays.sort(types);
int mapbase = -1;
@@ -149,7 +170,7 @@ public class TypeMap
for (int i = 0; i < types.length; i++)
{
int base = types[i] >> 8;
int base = (types[i] >> 8) & 0xFF;
if (base == mapbase) continue;
if (mapstart >= 0)
{

View File

@@ -33,7 +33,6 @@ import java.util.TreeMap;
import java.util.logging.Logger;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.NSEC3PARAMRecord;
import org.xbill.DNS.NSEC3Record;
import org.xbill.DNS.NSECRecord;
@@ -64,6 +63,7 @@ public class ZoneVerifier
private Name mZoneName;
private DNSSECType mDNSSECType;
private NSEC3PARAMRecord mNSEC3params;
private boolean mIgnoreDuplicateRRs;
private DnsSecVerifier mVerifier;
private base32 mBase32;
@@ -108,22 +108,49 @@ public class ZoneVerifier
mVerifier = new DnsSecVerifier();
mBase32 = new base32(base32.Alphabet.BASE32HEX, false, true);
mBAcmp = new ByteArrayComparator();
mIgnoreDuplicateRRs = false;
}
/** @return the DnsSecVerifier object used to verify individual RRsets. */
public DnsSecVerifier getVerifier()
{
return mVerifier;
}
public void setIgnoreDuplicateRRs(boolean value)
{
mIgnoreDuplicateRRs = value;
}
private static String key(Name n, int type)
{
return n.toString() + ':' + type;
}
@SuppressWarnings("rawtypes")
private boolean addRRtoRRset(RRset rrset, Record rr)
{
if (mIgnoreDuplicateRRs)
{
rrset.addRR(rr);
return true;
}
Iterator i = (rr instanceof RRSIGRecord) ? rrset.sigs() : rrset.rrs();
for ( ; i.hasNext(); )
{
Record record = (Record) i.next();
if (rr.equals(record)) return false;
}
rrset.addRR(rr);
return true;
}
/**
* Add a record to the various maps.
* @return TODO
*/
private void addRR(Record r)
private boolean addRR(Record r)
{
Name r_name = r.getName();
int r_type = r.getType();
@@ -139,8 +166,8 @@ public class ZoneVerifier
rrset = new MarkRRset();
mNSECMap.put(r_name, rrset);
}
rrset.addRR(r);
return;
return addRRtoRRset(rrset, r);
}
if (r_type == Type.NSEC3)
@@ -152,8 +179,8 @@ public class ZoneVerifier
rrset = new MarkRRset();
mNSEC3Map.put(r_name, rrset);
}
rrset.addRR(r);
return;
return addRRtoRRset(rrset, r);
}
// Add the name and type to the node map
@@ -173,7 +200,7 @@ public class ZoneVerifier
rrset = new RRset();
mRRsetMap.put(k, rrset);
}
rrset.addRR(r);
return addRRtoRRset(rrset, r);
}
/**
@@ -201,8 +228,9 @@ public class ZoneVerifier
* determine the NSEC3 parameters and signing type.
*
* @param records
* @return TODO
*/
private void calculateNodes(List<Record> records)
private int calculateNodes(List<Record> records)
{
mNodeMap = new TreeMap<Name, Set<Integer>>();
mRRsetMap = new HashMap<String, RRset>();
@@ -210,13 +238,19 @@ public class ZoneVerifier
// The zone is unsigned until we get a clue otherwise.
mDNSSECType = DNSSECType.UNSIGNED;
int errors = 0;
for (Record r : records)
{
Name r_name = r.getName();
int r_type = r.getType();
// Add the record to the various maps.
addRR(r);
boolean res = addRR(r);
if (!res)
{
log.warning("Record '" + r + "' detected as a duplicate");
errors++;
}
// Learn some things about the zone as we do this pass.
if (r_type == Type.SOA) mZoneName = r_name;
@@ -230,6 +264,8 @@ public class ZoneVerifier
if (mDNSSECType == DNSSECType.UNSIGNED) mDNSSECType = determineDNSSECType(r);
}
return errors;
}
/**
@@ -241,6 +277,11 @@ public class ZoneVerifier
// All RRs at the zone apex are normal
if (n.equals(mZoneName)) return NodeType.NORMAL;
// If the node is not below the zone itself, we will treat it as glue (it is really junk).
if (!n.subdomain(mZoneName))
{
return NodeType.GLUE;
}
// If the node is below a zone cut (either a delegation or DNAME), it is
// glue.
if (last_cut != null && n.subdomain(last_cut) && !n.equals(last_cut))
@@ -291,7 +332,7 @@ public class ZoneVerifier
last_cut = n;
}
// check all of the RRset that should be signed
// check all of the RRsets that should be signed
for (int type : typeset)
{
if (type == Type.RRSIG) continue;
@@ -354,24 +395,24 @@ public class ZoneVerifier
private int processRRset(RRset rrset)
{
List<String> reasons = new ArrayList<String>();
int result = DNSSEC.Failed;
boolean result = false;
for (Iterator<Record> i = rrset.sigs(); i.hasNext();)
{
RRSIGRecord sigrec = (RRSIGRecord) i.next();
byte res = mVerifier.verifySignature(rrset, sigrec, null, reasons);
if (res != DNSSEC.Secure)
boolean res = mVerifier.verifySignature(rrset, sigrec, reasons);
if (!res)
{
log.warning("Signature failed to verify RRset:\n rr: "
+ ZoneUtils.rrsetToString(rrset, false) + "\n sig: " + sigrec + "\n"
+ reasonListToString(reasons));
}
if (res > result) result = res;
if (res) result = res;
}
String rrsetname = rrset.getName() + "/" + Type.string(rrset.getType());
if (result == DNSSEC.Secure)
if (result)
{
log.fine("RRset " + rrsetname + " verified.");
}
@@ -380,7 +421,7 @@ public class ZoneVerifier
log.warning("RRset " + rrsetname + " did not verify.");
}
return result == DNSSEC.Secure ? 0 : 1;
return result ? 0 : 1;
}
private String typesToString(int[] types)
@@ -710,9 +751,9 @@ public class ZoneVerifier
{
int errors = 0;
calculateNodes(records);
errors += calculateNodes(records);
errors = processNodes();
errors += processNodes();
if (mDNSSECType == DNSSECType.NSEC)
{