initial import

git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@13 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
David Blacka 2005-08-13 23:18:03 +00:00
commit eb93599f0b
56 changed files with 5962 additions and 0 deletions

2
.cvsignore Normal file
View File

@ -0,0 +1,2 @@
build
*.tar.gz

51
README Normal file
View File

@ -0,0 +1,51 @@
java-dnssec-tools
http://www.dnssec.verisignlabs.com/
Author: David Blacka (davidb@verisignlabs.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.
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/signZone.sh -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,
particularly the use of the jikes compiler.
2. run Ant (see http://jakara.apache.org for information about the Ant
build tool).
% ant
---
Questions or comments may be directed to the author
(mailto:davidb@verisignlabs.com) or sent to the
dnssec@verisignlabs.com mailing list
(http://lists.verisignlabs.com/mailman/listinfo/dnssec).

3
VERSION Normal file
View File

@ -0,0 +1,3 @@
version=0.3.0
tagversion=0_3_0

27
bin/_makeDsSet.sh Executable file
View File

@ -0,0 +1,27 @@
#! /bin/sh
thisdir=`dirname $0`
basedir=`cd $thisdir/..; pwd`
ulimit -n `ulimit -H -n`
if [ x$JAVA_HOME = x ]; then
JAVA_HOME=/usr/local/jdk1.3
export JAVA_HOME
fi
LD_LIBRARY_PATH=${basedir}/obj:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH
# set the classpath
CLASSPATH=\
$JAVA_HOME/jre/lib/rt.jar:\
$basedir/obj/classes:\
$basedir/lib/dnsjava.jar:\
$basedir/lib/protomatter-1.1.5.jar:\
$basedir/lib/jdom-B6.jar:\
$basedir/lib/jce1_2_1.jar
export CLASSPATH
exec $JAVA_HOME/bin/java -Xmx64m com.nsi.dnssec.cl.MakeDSSet "$@"

27
bin/_makeKeySet.sh Executable file
View File

@ -0,0 +1,27 @@
#! /bin/sh
thisdir=`dirname $0`
basedir=`cd $thisdir/..; pwd`
ulimit -n `ulimit -H -n`
if [ x$JAVA_HOME = x ]; then
JAVA_HOME=/usr/local/jdk1.3
export JAVA_HOME
fi
LD_LIBRARY_PATH=${basedir}/obj:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH
# set the classpath
CLASSPATH=\
$JAVA_HOME/jre/lib/rt.jar:\
$basedir/obj/classes:\
$basedir/lib/dnsjava.jar:\
$basedir/lib/protomatter-1.1.5.jar:\
$basedir/lib/jdom-B6.jar:\
$basedir/lib/jce1_2_1.jar
export CLASSPATH
exec $JAVA_HOME/bin/java -Xmx64m com.nsi.dnssec.cl.MakeKeySet "$@"

14
bin/jdnssec-keygen Executable file
View File

@ -0,0 +1,14 @@
#! /bin/sh
thisdir=`dirname $0`
basedir=`cd $thisdir/..; pwd`
ulimit -n `ulimit -H -n`
# set the classpath
for i in $basedir/lib/*.jar $basedir/lib/*.zip; do
CLASSPATH="$CLASSPATH":"$i"
done
export CLASSPATH
exec java com.verisignlabs.dnssec.cl.KeyGen "$@"

14
bin/jdnssec-signzone Executable file
View File

@ -0,0 +1,14 @@
#! /bin/sh
thisdir=`dirname $0`
basedir=`cd $thisdir/..; pwd`
ulimit -n `ulimit -H -n`
# set the classpath
for i in $basedir/lib/*.jar $basedir/lib/*.zip; do
CLASSPATH="$CLASSPATH":"$i"
done
export CLASSPATH
exec java com.verisignlabs.dnssec.cl.SignZone "$@"

14
bin/jdnssec-verifyzone Executable file
View File

@ -0,0 +1,14 @@
#! /bin/sh
thisdir=`dirname $0`
basedir=`cd $thisdir/..; pwd`
ulimit -n `ulimit -H -n`
# set the classpath
for i in $basedir/lib/*.jar $basedir/lib/*.zip; do
CLASSPATH="$CLASSPATH":"$i"
done
export CLASSPATH
exec java com.verisignlabs.dnssec.cl.VerifyZone "$@"

3
build.properties Normal file
View File

@ -0,0 +1,3 @@
build.compiler=jikes
#build.compiler=modern
build.deprecation=true

176
build.xml Normal file
View File

@ -0,0 +1,176 @@
<?xml version="1.0"?>
<!--
build.xml for SECTOOLS
===================
Just run Ant using Ant's scripts ("ant") to compile. Once you
have done that, a "build/classes" directory will be created
containing the compiled class files.
-->
<project default="compile" basedir=".">
<property file="build.properties" />
<property file="VERSION" />
<property name="sectools-distname" value="java-dnssec-tools-${version}" />
<property name="build.dir" value="build" />
<property name="build.dest" value="${build.dir}/classes" />
<property name="build.lib.dest" value="${build.dir}/lib" />
<property name="build.src" value="src" />
<property name="packages" value="com.verisignlabs.dnssec.*" />
<property name="doc.dir" value="doc" />
<property name="javadoc.dest" value="${doc.dir}/javadoc" />
<property name="lib.dir" value="lib" />
<!-- set the standard classpath -->
<path id="project.classpath">
<pathelement location="${build.dest}" />
<fileset dir="${lib.dir}" includes="*.jar,*.zip" />
</path>
<property name="project.classpath" refid="project.classpath" />
<target name="prepare-src">
<mkdir dir="${build.dest}" />
<mkdir dir="${build.lib.dest}" />
</target>
<target name="sectools" depends="prepare-src" >
<javac srcdir="${build.src}"
destdir="${build.dest}"
classpathref="project.classpath"
deprecation="true"
includes="com/verisignlabs/dnssec/" />
</target>
<target name="sectools-jar" depends="usage,sectools">
<jar jarfile="${build.lib.dest}/java-dnssec-tools.jar"
basedir="${build.dest}"
includes="com/verisignlabs/dnssec/" />
</target>
<target name="compile"
depends="usage,sectools-jar">
</target>
<target name="javadoc" depends="usage">
<mkdir dir="${javadoc.dest}"/>
<javadoc packagenames="${packages}"
classpath="${project.classpath}"
sourcepath="${build.src}"
destdir="${javadoc.dest}"
verbose="true" author="true"
windowtitle="java-dnssec-tools-${version}"
use="true">
<link href="http://java.sun.com/j2se/1.4.2/docs/api/" />
<link href="http://www.xbill.org/dnsjava/doc/" />
</javadoc>
</target>
<target name="clean" depends="usage">
<delete dir="${build.dest}" />
<delete dir="${build.lib.dest}" />
</target>
<target name="sectools-dist-prepare" depends="usage, compile, javadoc">
<mkdir dir="${sectools-distname}" />
<copy todir="${sectools-distname}">
<fileset dir=".">
<include name="bin/jdnssec-*" />
<include name="lib/*.jar" />
<include name="lib/*.zip" />
<include name="doc/**" />
<include name="licenses/" />
<include name="src/**/*.java" />
<include name="VERSION" />
<include name="README" />
<include name="build.xml" />
<include name="build.properties" />
</fileset>
</copy>
<copy todir="${sectools-distname}/lib">
<fileset dir="${build.lib.dest}">
<include name="*.jar" />
</fileset>
</copy>
</target>
<target name="sectools-dist-clean">
<delete dir="${sectools-distname}" />
</target>
<patternset id="exec.files">
<!-- FIXME: when we get more command line tools built, make sure
to include them here -->
<include name="${sectools-distname}/bin/jdnssec-signzone" />
<include name="${sectools-distname}/bin/jdnssec-keygen" />
<include name="${sectools-distname}/bin/jdnssec-verifyzone" />
</patternset>
<patternset id="src.files">
<include name="${sectools-distname}/src/" />
<include name="${sectools-distname}/build.xml" />
<include name="${sectools-distname}/build.properties" />
</patternset>
<patternset id="bin.files">
<include name="${sectools-distname}/doc/" />
<include name="${sectools-distname}/lib/" />
<include name="${sectools-distname}/licenses/" />
<include name="${sectools-distname}/VERSION" />
<include name="${sectools-distname}/README" />
</patternset>
<target name="sectools-bin-dist" depends="sectools-dist-prepare">
<tar destfile="${sectools-distname}.tar.gz" compression="gzip">
<tarfileset mode="755" dir=".">
<patternset refid="exec.files" />
</tarfileset>
<tarfileset dir=".">
<patternset refid="bin.files" />
</tarfileset>
</tar>
</target>
<target name="sectools-src-dist" depends="sectools-dist-prepare">
<tar destfile="${sectools-distname}-src.tar.gz"
compression="gzip">
<tarfileset dir=".">
<patternset refid="src.files" />
</tarfileset>
</tar>
</target>
<target name="sectools-dist"
depends="sectools-bin-dist,sectools-src-dist, sectools-dist-clean">
</target>
<target name="dist" depends="sectools-dist">
<echo message="do not forget to tag the release:" />
<echo message=" cvs tag V_${tagversion}" />
</target>
<target name="usage">
<echo message=" " />
<echo message="SECTOOLS v. ${version} Build System" />
<echo message="--------------------------------" />
<echo message="Available Targets:" />
<echo message=" compile (default) - compiles the source code, creates jar" />
<echo message=" javadoc - create javadoc from source" />
<echo message=" clean - delete class files" />
<echo message=" dist - package it up" />
<echo message=" usage - this help message" />
<echo message=" " />
</target>
</project>

Binary file not shown.

Binary file not shown.

1
docs/.cvsignore Normal file
View File

@ -0,0 +1 @@
javadoc

BIN
lib/commons-cli-1.0.jar Normal file

Binary file not shown.

BIN
lib/commons-logging.jar Normal file

Binary file not shown.

BIN
lib/dnsjava-1.5.2.jar Normal file

Binary file not shown.

BIN
lib/jce1_2_2.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,60 @@
/*
* $Header: /home/radcvs/dnssec_pilot/sectools/licenses/commons-cli-LICENSE.txt,v 1.1 2003/04/02 22:40:49 davidb Exp $
* $Revision: 1.1 $
* $Date: 2003/04/02 22:40:49 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/

View File

@ -0,0 +1,60 @@
/*
* $Header: /home/radcvs/dnssec_pilot/sectools/licenses/commons-logging-LICENSE.txt,v 1.1 2003/04/02 22:40:49 davidb Exp $
* $Revision: 1.1 $
* $Date: 2003/04/02 22:40:49 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/

View File

@ -0,0 +1,36 @@
dnsjava is placed under the BSD license. Several files are also under
additional licenses; see the individual files for details.
Copyright (c) 1999-2003, Brian Wellington
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the dnsjava project nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Final notes:
- Thanks to Network Associates, Inc. for sponsoring some of the original
dnsjava work in 1999-2000.
- Thanks to Nominum, Inc. for sponsoring some work on dnsjava from 2000-2003.

View File

@ -0,0 +1,508 @@
jDNSSECtools Copyright (c) 2002 VeriSign, Inc.
jDNSSECtools is released under the following license:
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

169
licenses/jce-LICENSE.txt Normal file
View File

@ -0,0 +1,169 @@
Sun Microsystems, Inc.
Binary Code License Agreement
READ THE TERMS OF THIS AGREEMENT AND ANY PROVIDED SUPPLEMENTAL LICENSE
TERMS (COLLECTIVELY "AGREEMENT") CAREFULLY BEFORE OPENING THE SOFTWARE
MEDIA PACKAGE. BY OPENING THE SOFTWARE MEDIA PACKAGE, YOU AGREE TO THE
TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING THE SOFTWARE ELECTRONICALLY,
INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE "ACCEPT" BUTTON AT
THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL THESE TERMS,
PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF PURCHASE FOR A REFUND
OR, IF THE SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT THE "DECLINE" BUTTON
AT THE END OF THIS AGREEMENT.
1. LICENSE TO USE. Sun grants you a non-exclusive and non-transferable
license for the internal use only of the accompanying software and
documentation and any error corrections provided by Sun (collectively
"Software"), by the number of users and the class of computer hardware for
which the corresponding fee has been paid.
2. RESTRICTIONS. Software is confidential and copyrighted. Title to
Software and all associated intellectual property rights is retained by Sun
and/or its licensors. Except as specifically authorized in any
Supplemental License Terms, you may not make copies of Software, other than
a single copy of Software for archival purposes. Unless enforcement is
prohibited by applicable law, you may not modify, decompile, or reverse
engineer Software. You acknowledge that Software is not designed, licensed
or intended for use in the design, construction, operation or maintenance
of any nuclear facility. Sun disclaims any express or implied warranty of
fitness for such uses. No right, title or interest in or to any trademark,
service mark, logo or trade name of Sun or its licensors is granted under
this Agreement.
3. LIMITED WARRANTY. Sun warrants to you that for a period of ninety (90)
days from the date of purchase, as evidenced by a copy of the receipt, the
media on which Software is furnished (if any) will be free of defects in
materials and workmanship under normal use. Except for the foregoing,
Software is provided "AS IS". Your exclusive remedy and Sun's entire
liability under this limited warranty will be at Sun's option to replace
Software media or refund the fee paid for Software.
4. DISCLAIMER OF WARRANTY. UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS
OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE
DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
5. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR
DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT
OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no event will Sun's
liability to you, whether in contract, tort (including negligence), or
otherwise, exceed the amount paid by you for Software under this
Agreement. The foregoing limitations will apply even if the above stated
warranty fails of its essential purpose.
6. Termination. This Agreement is effective until terminated. You may
terminate this Agreement at any time by destroying all copies of Software.
This Agreement will terminate immediately without notice from Sun if you
fail to comply with any provision of this Agreement. Upon Termination, you
must destroy all copies of Software.
7. Export Regulations. All Software and technical data delivered under this
Agreement are subject to US export control laws and may be subject to
export or import regulations in other countries. You agree to comply
strictly with all such laws and regulations and acknowledge that you have
the responsibility to obtain such licenses to export, re-export, or import
as may be required after delivery to you.
8. U.S. Government Restricted Rights. If Software is being acquired by or
on behalf of the U.S. Government or by a U.S. Government prime contractor
or subcontractor (at any tier), then the Government's rights in Software
and accompanying documentation will be only as set forth in this Agreement;
this is in accordance with 48 CFR 227.7201 through 227.7202-4 (for
Department of Defense (DOD) acquisitions) and with 48 CFR 2.101 and 12.212
(for non-DOD acquisitions).
9. Governing Law. Any action related to this Agreement will be governed by
California law and controlling U.S. federal law. No choice of law rules of
any jurisdiction will apply.
10. Severability. If any provision of this Agreement is held to be
unenforceable, this Agreement will remain in effect with the provision
omitted, unless omission would frustrate the intent of the parties, in
which case this Agreement will immediately terminate.
11. Integration. This Agreement is the entire agreement between you and
Sun relating to its subject matter. It supersedes all prior or
contemporaneous oral or written communications, proposals, representations
and warranties and prevails over any conflicting or additional terms of any
quote, order, acknowledgment, or other communication between the parties
relating to its subject matter during the term of this Agreement. No
modification of this Agreement will be binding, unless in writing and
signed by an authorized representative of each party.
JAVA OPTIONAL PACKAGE
JAVATM CRYPTOGRAPHY EXTENSION, VERSION 1.2.2
SUPPLEMENTAL LICENSE TERMS
These supplemental license terms ("Supplemental Terms") add to or modify
the terms of the Binary Code License Agreement (collectively, the
"Agreement"). Capitalized terms not defined in these Supplemental Terms
shall have the same meanings ascribed to them in the Agreement. These
Supplemental Terms shall supersede any inconsistent or conflicting terms in
the Agreement, or in any license contained within the Software.
1. Software Internal Use and Development License Grant. Subject to the
terms and conditions of this Agreement, including, but not limited to
Section 3 (Java(TM) Technology Restrictions) of these Supplemental Terms,
Sun grants you a non-exclusive, non-transferable, limited license to
reproduce internally and use internally the binary form of the Software,
complete and unmodified, for the sole purpose of designing, developing and
testing your Java applets and applications ("Programs").
2. License to Distribute Software. In addition to the license granted in
Section 1 (Software Internal Use and Development License Grant) of these
Supplemental Terms, subject to the terms and conditions of this Agreement,
including but not limited to, Section 3 (Java Technology Restrictions) of
these Supplemental Terms, Sun grants you a non-exclusive, non-transferable,
limited license to reproduce and distribute the Software in binary code
form only, provided that you (i) distribute the Software complete and
unmodified and only bundled as part of your Programs, (ii) do not
distribute additional software intended to replace any component(s) of the
Software, (iii) do not remove or alter any proprietary legends or notices
contained in the Software, (iv) only distribute the Software subject to a
license agreement that protects Sun's interests consistent with the terms
contained in this Agreement, and (v) agree to defend and indemnify Sun and
its licensors from and against any damages, costs, liabilities, settlement
amounts and/or expenses (including attorneys' fees) incurred in connection
with any claim, lawsuit or action by any third party that arises or results
from the use or distribution of any and all Programs and/or Software.
3. Java Technology Restrictions. You may not modify the Java Platform
Interface ("JPI", identified as classes contained within the "java" package
or any subpackages of the "java" package), by creating additional classes
within the JPI or otherwise causing the addition to or modification of the
classes in the JPI. In the event that you create an additional class and
associated API(s) which (i) extends the functionality of the Java platform,
and (ii) is exposed to third party software developers for the purpose of
developing additional software which invokes such additional API, you must
promptly publish broadly an accurate specification for such API for free
use by all developers. You may not create, or authorize your licensees to
create additional classes, interfaces, or subpackages that are in any way
identified as "java", "javax", "sun" or similar convention as specified by
Sun in any naming convention designation.
4. Trademarks and Logos. You acknowledge and agree as between you and Sun
that Sun owns the SUN, SOLARIS, JAVA, JINI, FORTE, STAROFFICE, STARPORTAL
and iPLANET trademarks and all SUN, SOLARIS, JAVA, JINI, FORTE, STAROFFICE,
STARPORTAL and iPLANET-related trademarks, service marks, logos and other
brand designations ("Sun Marks"), and you agree to comply with the Sun
Trademark and Logo Usage Requirements currently located at
http://www.sun.com/policies/trademarks. Any use you make of the Sun Marks
inures to Sun's benefit.
5. Source Code. Software may contain source code that is provided solely
for reference purposes pursuant to the terms of this Agreement. Source
code may not be redistributed unless expressly provided for in this
Agreement.
6. Termination for Infringement. Either party may terminate this Agreement
immediately should any Software become, or in either party's opinion be
likely to become, the subject of a claim of infringement of any
intellectual property right.
For inquiries please contact: Sun Microsystems, Inc. 4150 Network Circle,
Santa Clara, California 95054
(LFI#113313/Form ID#011801)

View File

@ -0,0 +1,352 @@
// $Id: KeyGen.java,v 1.2 2004/01/16 17:56:17 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.cl;
import java.util.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.security.GeneralSecurityException;
import org.xbill.DNS.*;
import com.verisignlabs.dnssec.security.*;
import org.apache.commons.cli.*;
import org.apache.commons.cli.Options;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** This class forms the command line implementation of a DNSSEC key
* generator
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.2 $
*/
public class KeyGen
{
private static Log log;
/** This is a small inner class used to hold all of the command line
* option state. */
private static class CLIState
{
public int algorithm = 5;
public int keylength = 1024;
public String outputfile = null;
public File keydir = null;
public boolean zoneKey = true;
public boolean kskFlag = false;
public String owner = null;
public long ttl = 86400;
public CLIState() { }
public void parseCommandLine(Options opts, String[] args)
throws org.apache.commons.cli.ParseException, ParseException,
IOException
{
CommandLineParser cli_parser = new PosixParser();
CommandLine cli = cli_parser.parse(opts, args);
String optstr = null;
if (cli.hasOption('h')) usage(opts);
if (cli.hasOption('v'))
{
int value = parseInt(cli.getOptionValue('v'), 5);
switch (value)
{
case 0:
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
"fatal");
break;
case 5:
default:
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
"debug");
break;
case 6:
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
"trace");
break;
}
}
if (cli.hasOption('k')) kskFlag = true;
outputfile = cli.getOptionValue('f');
if ((optstr = cli.getOptionValue('d')) != null)
{
keydir = new File(optstr);
}
if ((optstr = cli.getOptionValue('n')) != null)
{
if (! optstr.equalsIgnoreCase("ZONE"))
{
zoneKey = false;
}
}
if ((optstr = cli.getOptionValue('a')) != null)
{
algorithm = parseAlg(optstr);
}
if ((optstr = cli.getOptionValue('b')) != null)
{
keylength = parseInt(optstr, 1024);
}
if ((optstr = cli.getOptionValue("ttl")) != null)
{
ttl = parseInt(optstr, 86400);
}
String[] cl_args = cli.getArgs();
if (cl_args.length < 1)
{
System.err.println("error: missing key owner name");
usage(opts);
}
owner = cl_args[0];
}
}
/** This is just a convenience method for parsing integers from
* strings.
*
* @param s the string to parse.
* @param def the default value, if the string doesn't parse.
* @return the parsed integer, or the default.
*/
private static int parseInt(String s, int def)
{
try
{
int v = Integer.parseInt(s);
return v;
}
catch (NumberFormatException e)
{
return def;
}
}
private static int parseAlg(String s)
{
int alg = parseInt(s, -1);
if (alg > 0) return alg;
s = s.toUpperCase();
if (s.equals("RSA"))
{
return DNSSEC.RSASHA1;
}
else if (s.equals("RSAMD5"))
{
return DNSSEC.RSA;
}
else if (s.equals("DH"))
{
return DNSSEC.DH;
}
else if (s.equals("DSA"))
{
return DNSSEC.DSA;
}
else if (s.equals("RSASHA1"))
{
return DNSSEC.RSASHA1;
}
// default
return DNSSEC.RSASHA1;
}
/** Set up the command line options.
*
* @return a set of command line options.
*/
private static Options setupCLI()
{
Options options = new Options();
// boolean options
options.addOption("h", "help", false, "Print this message.");
options.addOption("k", "kskflag", false,
"Key is a key-signing-key (sets the SEP flag).");
// Argument options
options.addOption(OptionBuilder.hasArg()
.withLongOpt("nametype")
.withArgName("type")
.withDescription("ZONE | OTHER (default ZONE)")
.create('n'));
options.addOption(OptionBuilder.hasOptionalArg()
.withLongOpt("verbose")
.withArgName("level")
.withDescription("verbosity level -- 0 is silence, " +
"5 is debug information, " +
"6 is trace information.\n"+
"default is level 5.")
.create('v'));
options.addOption(OptionBuilder.hasArg()
.withArgName("algorithm")
.withDescription("RSA | RSASHA1 | RSAMD5 | DH | DSA, " +
"RSASHA1 is default.")
.create('a'));
options.addOption(OptionBuilder.hasArg()
.withArgName("size")
.withDescription
("key size, in bits. (default = 1024)\n" +
"RSA|RSASHA1|RSAMD5: [512..4096]\n" +
"DSA: [512..1024]\n" +
"DH: [128..4096]")
.create('b'));
options.addOption(OptionBuilder.hasArg()
.withArgName("file")
.withLongOpt("output-file")
.withDescription
("base filename for the public/private key files")
.create('f'));
options.addOption(OptionBuilder.hasArg()
.withLongOpt("keydir")
.withArgName("dir")
.withDescription
("place generated key files in this directory")
.create('d'));
return options;
}
/** Print out the usage and help statements, then quit. */
private static void usage(Options opts)
{
HelpFormatter f = new HelpFormatter();
PrintWriter out = new PrintWriter(System.err);
// print our own usage statement:
f.printHelp(out, 75, "keyGen.sh [..options..] name", null, opts,
HelpFormatter.DEFAULT_LEFT_PAD,
HelpFormatter.DEFAULT_DESC_PAD, null);
out.flush();
System.exit(64);
}
public static void execute(CLIState state, Options opts)
throws Exception
{
JCEDnsSecSigner signer = new JCEDnsSecSigner();
// Minor hack to make the owner name absolute.
if (! state.owner.endsWith("."))
{
state.owner = state.owner + ".";
}
Name owner_name = Name.fromString(state.owner);
// Calculate our flags
int flags = 0;
if (state.zoneKey) flags |= DNSKEYRecord.OWNER_ZONE;
if (state.kskFlag) flags |= DNSKEYRecord.FLAG_SEP;
log.debug("create key pair with (name = " + owner_name + ", ttl = " +
state.ttl + ", alg = " + state.algorithm + ", flags = " +
flags + ", length = " + state.keylength + ")");
DnsKeyPair pair = signer.generateKey(owner_name,
state.ttl,
DClass.IN,
state.algorithm,
flags,
state.keylength);
if (state.outputfile != null)
{
BINDKeyUtils.writeKeyFiles(state.outputfile, pair, state.keydir);
}
else
{
BINDKeyUtils.writeKeyFiles(pair, state.keydir);
}
}
public static void main(String[] args)
{
// set up logging.
// For now, we force the commons logging to use the built-in
// SimpleLog.
System.setProperty("org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.SimpleLog");
// set up the command line options
Options opts = setupCLI();
CLIState state = new CLIState();
try
{
state.parseCommandLine(opts, args);
}
catch (UnrecognizedOptionException e)
{
System.err.println("error: unknown option encountered: " +
e.getMessage());
usage(opts);
}
catch (AlreadySelectedException e)
{
System.err.println("error: mutually exclusive options have " +
"been selected:\n " + e.getMessage());
usage(opts);
}
catch (Exception e)
{
System.err.println("error: unknown command line parsing exception:");
e.printStackTrace();
usage(opts);
}
log = LogFactory.getLog(KeyGen.class);
try
{
execute(state, opts);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,719 @@
// $Id: SignZone.java,v 1.4 2004/01/16 17:57:47 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.cl;
import java.util.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.security.GeneralSecurityException;
import org.xbill.DNS.*;
import com.verisignlabs.dnssec.security.*;
import org.apache.commons.cli.*;
import org.apache.commons.cli.Options;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** This class forms the command line implementation of a DNSSEC zone
* signer.
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.4 $
*/
public class SignZone
{
private static Log log;
/** This is a small inner class used to hold all of the command line
* option state. */
private static class CLIState
{
private File keyDirectory = null;
public File keysetDirectory = null;
public String[] kskFiles = null;
public String[] keyFiles = null;
public String zonefile = null;
public Date start = null;
public Date expire = null;
public String outputfile = null;
public boolean verifySigs = false;
public boolean selfSignKeys = true;
public boolean useOptIn = false;
public boolean optInConserve = false;
public boolean fullySignKeyset = false;
public List includeNames = null;
public CLIState() { }
public void parseCommandLine(Options opts, String[] args)
throws org.apache.commons.cli.ParseException, ParseException,
IOException
{
CommandLineParser cli_parser = new PosixParser();
CommandLine cli = cli_parser.parse(opts, args);
String optstr = null;
if (cli.hasOption('h')) usage(opts);
if (cli.hasOption('v'))
{
int value = parseInt(cli.getOptionValue('v'), 5);
switch (value)
{
case 0:
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
"fatal");
break;
case 5:
default:
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
"debug");
break;
case 6:
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
"trace");
break;
}
}
if (cli.hasOption('a')) verifySigs = true;
if (cli.hasOption('O')) useOptIn = true;
if (cli.hasOption('C'))
{
useOptIn = true;
optInConserve = true;
}
if (cli.hasOption('F')) fullySignKeyset = true;
if ((optstr = cli.getOptionValue('d')) != null)
{
keysetDirectory = new File(optstr);
if (! keysetDirectory.isDirectory())
{
System.err.println("error: " + optstr + " is not a directory");
usage(opts);
}
}
if ((optstr = cli.getOptionValue('D')) != null)
{
keyDirectory = new File(optstr);
if (! keyDirectory.isDirectory())
{
System.err.println("error: " + optstr + " is not a directory");
usage(opts);
}
}
if ((optstr = cli.getOptionValue('s')) != null)
{
start = convertDuration(null, optstr);
}
else
{
// default is now - 1 hour.
start = new Date(System.currentTimeMillis() - (3600 * 1000));
}
if ((optstr = cli.getOptionValue('e')) != null)
{
expire = convertDuration(start, optstr);
}
else
{
expire = convertDuration(start, "+2592000"); // 30 days
}
outputfile = cli.getOptionValue('f');
kskFiles = cli.getOptionValues('k');
if ((optstr = cli.getOptionValue('I')) != null)
{
File includeNamesFile = new File(optstr);
includeNames = getNameList(includeNamesFile);
}
String[] files = cli.getArgs();
if (files.length < 2)
{
System.err.println("error: missing zone file and/or key files");
usage(opts);
}
zonefile = files[0];
keyFiles = new String[files.length - 1];
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
}
}
/** This is just a convenience method for parsing integers from
* strings.
*
* @param s the string to parse.
* @param def the default value, if the string doesn't parse.
* @return the parsed integer, or the default.
*/
private static int parseInt(String s, int def)
{
try
{
int v = Integer.parseInt(s);
return v;
}
catch (NumberFormatException e)
{
return def;
}
}
/** Verify the generated signatures.
*
* @param zonename the origin name of the zone.
* @param records a list of {@link org.xbill.DNS.Record}s.
* @param keypairs a list of keypairs used the sign the zone.
* @return true if all of the signatures validated.
*/
private static boolean verifyZoneSigs(Name zonename, List records,
List keypairs)
{
boolean secure = true;
DnsSecVerifier verifier = new DnsSecVerifier();
for (Iterator i = keypairs.iterator(); i.hasNext(); )
{
verifier.addTrustedKey((DnsKeyPair) i.next());
}
verifier.setVerifyAllSigs(true);
List rrsets = SignUtils.assembleIntoRRsets(records);
for (Iterator i = rrsets.iterator(); i.hasNext(); )
{
RRset rrset = (RRset) i.next();
// skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue;
byte result = verifier.verify(rrset, null);
if (result != DNSSEC.Secure)
{
log.debug("Signatures did not verify for RRset: (" + result + "): " +
rrset);
secure = false;
}
}
return secure;
}
/** Load the key pairs from the key files.
*
* @param keyfiles a string array containing the base names or
* paths of the keys to be loaded.
* @param start_index the starting index of keyfiles string array
* to use. This allows us to use the straight command line
* argument array.
* @param inDirectory the directory to look in (may be null).
* @return a list of keypair objects.
*/
private static List getKeys(String[] keyfiles, int start_index,
File inDirectory)
throws IOException
{
if (keyfiles == null) return null;
int len = keyfiles.length - start_index;
if (len <= 0) return null;
ArrayList keys = new ArrayList(len);
for (int i = start_index; i < keyfiles.length; i++)
{
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
if (k != null) keys.add(k);
}
return keys;
}
/** Load a single key from a given keyfile.
*
* @param keyfile the keyfile.
* @param inDirectory the default directory to look in (may be
* null).
* @return a list containing one or zero keypair objects.
*/
private static List getKeys(File keyfile, File inDirectory)
throws IOException
{
if (keyfile == null) return null;
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfile.getPath(),
inDirectory);
if (k != null)
{
ArrayList keys = new ArrayList(1);
keys.add(k);
return keys;
}
return null;
}
/** This is an implementation of a file filter used for finding BIND
* 9-style keyset-* files. */
private static class KeysetFileFilter implements FileFilter
{
public boolean accept(File pathname)
{
if (! pathname.isFile()) return false;
String name = pathname.getName();
if (name.startsWith("keyset-")) return true;
return false;
}
}
/** Load keysets (which contain delegation point security info).
*
* @param inDirectory the directory to look for the keyset files
* (may be null, in which case it defaults to looking in the
* current working directory).
* @param zonename the name of the zone we are signing, so we can
* ignore keysets that do not belong in the zone.
* @return a list of {@link org.xbill.DNS.Record}s found in the
* keyset files.
*/
private static List getKeysets(File inDirectory, Name zonename)
throws IOException
{
if (inDirectory == null)
{
// FIXME: dunno how cross-platform this is
inDirectory = new File(".");
}
// get the list of "keyset-" files.
FileFilter filter = new KeysetFileFilter();
File[] files = inDirectory.listFiles(filter);
// read in all of the records
ArrayList keysetRecords = new ArrayList();
for (int i = 0; i < files.length; i++)
{
List l = ZoneUtils.readZoneFile(files[i].getAbsolutePath(), zonename);
keysetRecords.addAll(l);
}
// discard records that do not belong to the zone in question.
for (Iterator i = keysetRecords.iterator(); i.hasNext(); )
{
Record r = (Record) i.next();
if (!r.getName().subdomain(zonename))
{
i.remove();
}
}
return keysetRecords;
}
/** Load a list of DNS names from a file.
*
* @param nameListFile the path of a file containing a bare list of
* DNS names.
* @return a list of {@link org.xbill.DNS.Name} objects.
*/
private static List getNameList(File nameListFile)
throws IOException
{
BufferedReader br = new BufferedReader(new FileReader(nameListFile));
List res = new ArrayList();
String line = null;
while ( (line = br.readLine()) != null )
{
try
{
Name n = Name.fromString(line);
// force the name to be absolute.
// FIXME: we should probably get some fancy logic here to
// detect if the name needs the origin appended, or just the
// root.
if (! n.isAbsolute()) n = Name.concatenate(n, Name.root);
res.add(n);
}
catch (TextParseException e)
{
log.error("DNS Name parsing error", e);
}
}
if (res.size() == 0) return null;
return res;
}
/** Calculate a date/time from a command line time/offset duration string.
*
* @param start the start time to calculate offsets from.
* @param duration the time/offset string to parse.
* @return the calculated time.
*/
private static Date convertDuration(Date start, String duration)
throws ParseException
{
if (start == null) start = new Date();
if (duration.startsWith("now"))
{
start = new Date();
if (duration.indexOf("+") < 0) return start;
duration = duration.substring(3);
}
if (duration.startsWith("+"))
{
long offset = (long) parseInt(duration.substring(1), 0) * 1000;
return new Date(start.getTime() + offset);
}
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
return dateFormatter.parse(duration);
}
/** Determine if the given keypairs can be used to sign the zone.
* @param zonename the zone origin.
* @param keypairs a list of {@link DnsKeyPair} objects that will
* be used to sign the zone.
* @return true if the keypairs valid.
*/
private static boolean keyPairsValidForZone(Name zonename, List keypairs)
{
if (keypairs == null) return true; // technically true, I guess.
for (Iterator i = keypairs.iterator(); i.hasNext(); )
{
DnsKeyPair kp = (DnsKeyPair) i.next();
Name keyname = kp.getDNSKEYRecord().getName();
if (!keyname.equals(zonename))
{
return false;
}
}
return true;
}
/** Set up the command line options.
*
* @return a set of command line options.
*/
private static Options setupCLI()
{
Options options = new Options();
// boolean options
options.addOption("h", "help", false, "Print this message.");
options.addOption("a", false, "verify generated signatures>");
options.addOption("F", "fully-sign-keyset", false,
"sign the zone apex keyset with all " +
"available keys, instead of just key-signing-keys.");
// Opt-In generation switches
OptionGroup opt_in_opts = new OptionGroup();
opt_in_opts.addOption(new Option
("O", "generate a fully Opt-In zone."));
opt_in_opts.addOption(new Option
("C", "generate a conservative Opt-In zone."));
options.addOptionGroup(opt_in_opts);
// Argument options
options.addOption(OptionBuilder.hasOptionalArg()
.withArgName("level")
.withDescription("verbosity level -- 0 is silence, " +
"5 is debug information, " +
"6 is trace information. " +
"No argument means 5.")
.create('v'));
options.addOption(OptionBuilder.hasArg()
.withArgName("dir")
.withLongOpt("keyset-directory")
.withDescription
("directory to find keyset files (default '.').")
.create('d'));
options.addOption(OptionBuilder.hasArg()
.withArgName("dir")
.withLongOpt("key-directory")
.withDescription
("directory to find key files (default '.').")
.create('D'));
options.addOption(OptionBuilder.hasArg()
.withArgName("time/offset")
.withLongOpt("start-time")
.withDescription
("signature starting time (default is now - 1 hour)")
.create('s'));
options.addOption(OptionBuilder.hasArg()
.withArgName("time/offset")
.withLongOpt("expire-time")
.withDescription
("signature expiration time (default is " +
"start-time + 30 days")
.create('e'));
options.addOption(OptionBuilder.hasArg()
.withArgName("outfile")
.withDescription("file the signed zone is written " +
"to (default is <origin>.signed).")
.create('f'));
options.addOption(OptionBuilder.hasArgs()
.withArgName("KSK file")
.withLongOpt("ksk-file")
.withDescription("this key is a key signing key " +
"(may repeat)")
.create('k'));
options.addOption(OptionBuilder.hasArg()
.withArgName("file")
.withLongOpt("include-file")
.withDescription("include names in this file " +
"in the NSEC chain")
.create('I'));
return options;
}
/** Print out the usage and help statements, then quit. */
private static void usage(Options opts)
{
HelpFormatter f = new HelpFormatter();
PrintWriter out = new PrintWriter(System.err);
// print our own usage statement:
out.println("usage: signZone.sh [..options..] zone_file [key_file ...] ");
f.printHelp(out, 75, "signZone.sh", null, opts,
HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD,
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
out.flush();
System.exit(64);
}
public static void execute(CLIState state, Options opts)
throws Exception
{
// Load the key pairs.
// FIXME: should we do what BIND 9.3.x snapshots do and look at
// zone apex DNSKEY RRs, and from that be able to load all of the
// keys?
List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
List kskpairs = getKeys(state.kskFiles, 0, state.keyDirectory);
// If we don't have any KSKs, but we do have more than one zone
// signing key (presumably), presume that the zone signing keys
// are just not differentiated and try to figure out which keys
// are actually ksks by looking at the SEP flag.
if ( (kskpairs == null || kskpairs.size() == 0) &&
keypairs != null && keypairs.size() > 1)
{
for (Iterator i = keypairs.iterator(); i.hasNext(); )
{
DnsKeyPair pair = (DnsKeyPair) i.next();
DNSKEYRecord kr = pair.getDNSKEYRecord();
if ((kr.getFlags() & DNSKEYRecord.FLAG_SEP) != 0)
{
if (kskpairs == null) kskpairs = new ArrayList();
kskpairs.add(pair);
i.remove();
}
}
}
// Read in the zone
List records = ZoneUtils.readZoneFile(state.zonefile, null);
if (records == null || records.size() == 0)
{
System.err.println("error: empty zone file");
usage(opts);
}
// calculate the zone name.
Name zonename = ZoneUtils.findZoneName(records);
if (zonename == null)
{
System.err.println("error: invalid zone file - no SOA");
usage(opts);
}
// default the output file, if not set.
if (state.outputfile == null)
{
if (zonename.isAbsolute())
{
state.outputfile = zonename + "signed";
}
else
{
state.outputfile = zonename + ".signed";
}
}
// Verify that the keys can be in the zone.
List kpairs = keypairs;
if (!keyPairsValidForZone(zonename, keypairs) ||
!keyPairsValidForZone(zonename, kskpairs))
{
usage(opts);
}
// We force the signing keys to be in the zone by just appending
// them to the zone here. Currently JCEDnsSecSigner.signZone
// removes duplicate records.
if (kskpairs != null)
{
for (Iterator i = kskpairs.iterator(); i.hasNext(); )
{
records.add( ((DnsKeyPair) i.next()).getDNSKEYRecord() );
}
}
if (keypairs != null)
{
for (Iterator i = keypairs.iterator(); i.hasNext(); )
{
records.add( ((DnsKeyPair) i.next()).getDNSKEYRecord() );
}
}
// read in the keysets, if any.
List keysetrecs = getKeysets(state.keysetDirectory, zonename);
if (keysetrecs != null)
{
records.addAll(keysetrecs);
}
JCEDnsSecSigner signer = new JCEDnsSecSigner();
// Sign the zone.
List signed_records = signer.signZone(zonename,
records,
kskpairs,
keypairs,
state.start,
state.expire,
state.useOptIn,
state.optInConserve,
state.fullySignKeyset,
state.includeNames);
// write out the signed zone
// force multiline mode for now
org.xbill.DNS.Options.set("multiline");
ZoneUtils.writeZoneFile(signed_records, state.outputfile);
if (state.verifySigs)
{
// FIXME: ugh.
if (kskpairs != null)
{
keypairs.addAll(kskpairs);
}
log.debug("verifying generated signatures");
boolean res = verifyZoneSigs(zonename, signed_records, keypairs);
if (res)
{
System.out.println("Generated signatures verified");
// log.info("Generated signatures verified");
}
else
{
System.out.println("Generated signatures did not verify.");
// log.warn("Generated signatures did not verify.");
}
}
}
public static void main(String[] args)
{
// set up logging.
// For now, we force the commons logging to use the built-in
// SimpleLog.
System.setProperty("org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.SimpleLog");
// set up the command line options
Options opts = setupCLI();
CLIState state = new CLIState();
try
{
state.parseCommandLine(opts, args);
}
catch (UnrecognizedOptionException e)
{
System.err.println("error: unknown option encountered: " +
e.getMessage());
usage(opts);
}
catch (AlreadySelectedException e)
{
System.err.println("error: mutually exclusive options have " +
"been selected:\n " + e.getMessage());
usage(opts);
}
catch (Exception e)
{
System.err.println("error: unknown command line parsing exception:");
e.printStackTrace();
usage(opts);
}
log = LogFactory.getLog(SignZone.class);
try
{
execute(state, opts);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,331 @@
// $Id: VerifyZone.java,v 1.1 2004/01/16 17:57:59 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.cl;
import java.util.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.security.GeneralSecurityException;
import org.xbill.DNS.*;
import com.verisignlabs.dnssec.security.*;
import org.apache.commons.cli.*;
import org.apache.commons.cli.Options;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** This class forms the command line implementation of a DNSSEC zone
* validator.
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.1 $
*/
public class VerifyZone
{
private static Log log;
/** This is a small inner class used to hold all of the command line
* option state. */
private static class CLIState
{
public boolean strict = false;
public File keydir = null;
public String zonefile = null;
public String[] keyfiles = null;
public CLIState() { }
public void parseCommandLine(Options opts, String[] args)
throws org.apache.commons.cli.ParseException, ParseException,
IOException
{
CommandLineParser cli_parser = new PosixParser();
CommandLine cli = cli_parser.parse(opts, args);
String optstr = null;
if (cli.hasOption('h')) usage(opts);
if (cli.hasOption('v'))
{
int value = parseInt(cli.getOptionValue('v'), 5);
switch (value)
{
case 0:
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
"fatal");
break;
case 5:
default:
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
"debug");
break;
case 6:
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
"trace");
break;
}
}
if (cli.hasOption('s')) strict = true;
if ((optstr = cli.getOptionValue('d')) != null)
{
keydir = new File(optstr);
}
String[] cl_args = cli.getArgs();
if (cl_args.length < 1)
{
System.err.println("error: missing zone file");
usage(opts);
}
zonefile = cl_args[0];
if (cl_args.length < 2)
{
System.err.println("error: at least one trusted key is required");
usage(opts);
}
keyfiles = new String[cl_args.length - 1];
System.arraycopy(cl_args, 1, keyfiles, 0, keyfiles.length);
}
}
/** This is just a convenience method for parsing integers from
* strings.
*
* @param s the string to parse.
* @param def the default value, if the string doesn't parse.
* @return the parsed integer, or the default.
*/
private static int parseInt(String s, int def)
{
try
{
int v = Integer.parseInt(s);
return v;
}
catch (NumberFormatException e)
{
return def;
}
}
/** Set up the command line options.
*
* @return a set of command line options.
*/
private static Options setupCLI()
{
Options options = new Options();
// boolean options
options.addOption("h", "help", false, "Print this message.");
options.addOption("s", "strict", false,
"Zone will only be considered valid if all " +
"signatures could be cryptographically verified");
// Argument options
options.addOption(OptionBuilder.hasArg()
.withLongOpt("keydir")
.withArgName("dir")
.withDescription("directory to find trusted key files")
.create('d'));
options.addOption(OptionBuilder.hasOptionalArg()
.withLongOpt("verbose")
.withArgName("level")
.withDescription("verbosity level -- 0 is silence, " +
"5 is debug information, " +
"6 is trace information.\n" +
"default is level 5.")
.create('v'));
return options;
}
/** Print out the usage and help statements, then quit. */
private static void usage(Options opts)
{
HelpFormatter f = new HelpFormatter();
PrintWriter out = new PrintWriter(System.err);
// print our own usage statement:
f.printHelp(out, 75,
"verifyZone.sh [..options..] zonefile " +
"keyfile [keyfile...]", null, opts,
HelpFormatter.DEFAULT_LEFT_PAD,
HelpFormatter.DEFAULT_DESC_PAD, null);
out.flush();
System.exit(64);
}
private static byte verifyZoneSignatures(List records, List keypairs)
{
// Zone is secure until proven otherwise.
byte result = DNSSEC.Secure;
DnsSecVerifier verifier = new DnsSecVerifier();
for (Iterator i = keypairs.iterator(); i.hasNext(); )
{
verifier.addTrustedKey((DnsKeyPair) i.next());
}
List rrsets = SignUtils.assembleIntoRRsets(records);
for (Iterator i = rrsets.iterator(); i.hasNext(); )
{
RRset rrset = (RRset) i.next();
// We verify each signature separately so that we can report
// which exact signature failed.
for (Iterator j = rrset.sigs(); j.hasNext(); )
{
Object o = j.next();
if (! (o instanceof RRSIGRecord))
{
log.debug("found " + o + " where expecting a RRSIG");
continue;
}
RRSIGRecord sigrec = (RRSIGRecord) o;
byte res = verifier.verifySignature(rrset, sigrec, null);
if (res != DNSSEC.Secure)
{
log.info("Signature failed to verify RRset: " + rrset + "\nsig: " + sigrec);
}
if (res < result) result = res;
}
}
return result;
}
private static List getTrustedKeys(String[] keyfiles, File inDirectory)
throws IOException
{
if (keyfiles == null) return null;
List keys = new ArrayList(keyfiles.length);
for (int i = 0; i < keyfiles.length; i++)
{
DnsKeyPair pair = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
if (pair != null) keys.add(pair);
}
return keys;
}
public static void execute(CLIState state, Options opts)
throws Exception
{
List keypairs = getTrustedKeys(state.keyfiles, state.keydir);
List records = ZoneUtils.readZoneFile(state.zonefile, null);
Collections.sort(records, new RecordComparator());
log.debug("verifying signatures...");
byte result = verifyZoneSignatures(records, keypairs);
log.debug("completed verification process.");
switch (result)
{
case DNSSEC.Failed:
System.out.println("zone did not verify.");
System.exit(1);
break;
case DNSSEC.Insecure:
if (state.strict)
{
System.out.println("zone did not verify.");
System.exit(1);
}
case DNSSEC.Secure:
System.out.println("zone verified.");
break;
}
System.exit(0);
}
public static void main(String[] args)
{
// set up logging.
// For now, we force the commons logging to use the built-in
// SimpleLog.
System.setProperty("org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.SimpleLog");
// set up the command line options
Options opts = setupCLI();
CLIState state = new CLIState();
try
{
state.parseCommandLine(opts, args);
}
catch (UnrecognizedOptionException e)
{
System.err.println("error: unknown option encountered: " +
e.getMessage());
usage(opts);
}
catch (AlreadySelectedException e)
{
System.err.println("error: mutually exclusive options have " +
"been selected:\n " + e.getMessage());
usage(opts);
}
catch (Exception e)
{
System.err.println("error: unknown command line parsing exception:");
e.printStackTrace();
usage(opts);
}
log = LogFactory.getLog(VerifyZone.class);
try
{
execute(state, opts);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,33 @@
<BODY BGCOLOR="#FFFFFF">
java-dnssec-tools is a collection of Java-based command line tools for
managing DNSSEC zones and keys.
<p>
<center>
<table width="90%" border=1 cellpadding=10 cellspacing=0>
<tr><td class="TableRowColor">
Copyright &copy; 2003 Verisign, Inc. by
<a href="mailto:davidb@verisignlabs.com">David Blacka</a><P>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.<P>
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.<P>
You should have received a copy of the
<a href="http://www.gnu.org/copyleft/lgpl.html">GNU Library General Public License</a>
along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
</td></tr>
</table><P>
</center>
</BODY>

View File

@ -0,0 +1,398 @@
// $Id: BINDKeyUtils.java,v 1.5 2004/02/25 20:46:14 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.security;
import java.io.*;
import java.security.*;
import java.text.NumberFormat;
import org.xbill.DNS.*;
import org.xbill.DNS.utils.base64;
/** This class contains a series of static methods used for
* manipulating BIND 9.x.x-style DNSSEC key files.
*
* In this class, the "base" key path or name is the file name
* without the trailing ".key" or ".private".
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.5 $
*/
public class BINDKeyUtils
{
// formatters used to generated the BIND key file names
private static NumberFormat mAlgNumberFormatter;
private static NumberFormat mKeyIdNumberFormatter;
/** Calculate the BIND9 key file base name (i.e., without the ".key"
* or ".private" extensions) */
private static String getKeyFileBase(Name signer, int algorithm,
int keyid)
{
if (mAlgNumberFormatter == null)
{
mAlgNumberFormatter = NumberFormat.getNumberInstance();
mAlgNumberFormatter.setMaximumIntegerDigits(3);
mAlgNumberFormatter.setMinimumIntegerDigits(3);
}
if (mKeyIdNumberFormatter == null)
{
mKeyIdNumberFormatter = NumberFormat.getNumberInstance();
mKeyIdNumberFormatter.setMaximumIntegerDigits(5);
mKeyIdNumberFormatter.setMinimumIntegerDigits(5);
mKeyIdNumberFormatter.setGroupingUsed(false);
}
keyid &= 0xFFFF;
String fn = "K" + signer + "+" +
mAlgNumberFormatter.format(algorithm) +
"+" +
mKeyIdNumberFormatter.format(keyid);
return fn;
}
/** Reads in the KEYRecord from the public key file */
private static DNSKEYRecord loadPublicKeyFile(File publicKeyFile)
throws IOException
{
Master m = new Master(publicKeyFile.getAbsolutePath(), null, 600);
Record r;
DNSKEYRecord result = null;
while ( (r = m.nextRecord()) != null )
{
if (r.getType() == Type.DNSKEY)
{
result = (DNSKEYRecord) r;
}
}
return result;
}
/** Reads in the private key verbatim from the private key file */
private static String loadPrivateKeyFile(File privateKeyFile)
throws IOException
{
BufferedReader in = new BufferedReader(new FileReader(privateKeyFile));
StringBuffer key_buf = new StringBuffer();
String line;
while ( (line = in.readLine()) != null)
{
key_buf.append(line);
key_buf.append('\n');
}
return key_buf.toString().trim();
}
/** Given an actual path for one of the key files, return the base
* name */
private static String fixKeyFileBasePath(String basePath)
{
if (basePath == null) throw new IllegalArgumentException();
if (basePath.endsWith(".key") ||
basePath.endsWith(".private"))
{
basePath = basePath.substring
(0, basePath.lastIndexOf("."));
}
return basePath;
}
/** Given the information necessary to construct the path to a BIND9
* generated key pair, load the key pair.
*
* @param signer the DNS name of the key.
* @param algorithm the DNSSEC algorithm of the key.
* @param keyid the DNSSEC key footprint.
* @param inDirectory the directory to look for the files (may be
* null).
* @return the loaded key pair.
* @throws IOException if there was a problem reading the BIND9
* files. */
public static DnsKeyPair loadKeyPair(Name signer, int algorithm,
int keyid, File inDirectory)
throws IOException
{
String keyFileBase = getKeyFileBase(signer, algorithm, keyid);
return loadKeyPair(keyFileBase, inDirectory);
}
/** Given a base path to a BIND9 key pair, load the key pair.
*
* @param keyFileBasePath the base filename (or real filename for
* either the public or private key) of the key.
* @param inDirectory the directory to look in, if the
* keyFileBasePath is relative.
* @return the loaded key pair.
* @throws IOException if there was a problem reading the files */
public static DnsKeyPair loadKeyPair(String keyFileBasePath,
File inDirectory)
throws IOException
{
keyFileBasePath = fixKeyFileBasePath(keyFileBasePath);
// FIXME: should we throw the IOException when one of the files
// cannot be found, or just when both cannot be found?
File publicKeyFile = new File(inDirectory, keyFileBasePath + ".key");
File privateKeyFile = new File(inDirectory, keyFileBasePath + ".private");
DnsKeyPair kp = new DnsKeyPair();
DNSKEYRecord kr = loadPublicKeyFile(publicKeyFile);
kp.setDNSKEYRecord(kr);
String pk = loadPrivateKeyFile(privateKeyFile);
kp.setPrivateKeyString(pk);
return kp;
}
/** Given a base path to a BIND9 key pair, load the public part
* (only) of the key pair
*
* @param keyFileBasePath the base or real path to the public part
* of a key pair.
* @param inDirectory the directory to look in if the path is
* relative (may be null).
* @return a {@link DnsKeyPair} containing just the public key
* information.
* @throws IOException if there was a problem reading the public
* key file.
*/
public static DnsKeyPair loadKey(String keyFileBasePath, File inDirectory)
throws IOException
{
keyFileBasePath = fixKeyFileBasePath(keyFileBasePath);
File publicKeyFile = new File(inDirectory, keyFileBasePath + ".key");
DnsKeyPair kp = new DnsKeyPair();
DNSKEYRecord kr = loadPublicKeyFile(publicKeyFile);
kp.setDNSKEYRecord(kr);
return kp;
}
/** Load a BIND keyset file. The BIND 9 dnssec tools typically call
* these files "keyset-[signer]." where [signer] is the DNS owner
* name of the key. The keyset may be signed, but doesn't have to
* be.
*
* @param keysetFileName the name of the keyset file.
* @param inDirectory the directory to look in if the path is
* relative (may be null, defaults to the current working
* directory).
* @return a RRset contain the KEY records and any associated SIG records.
* @throws IOException if there was a problem reading the keyset
* file.
*/
public static RRset loadKeySet(String keysetFileName, File inDirectory)
throws IOException
{
File keysetFile = new File(inDirectory, keysetFileName);
Master m = new Master(keysetFile.getAbsolutePath());
Record r;
RRset keyset = new RRset();
while ( (r = m.nextRecord()) != null )
{
keyset.addRR(r);
}
return keyset;
}
/** Calculate the key file base for this key pair.
*
* @param pair the {@link DnsKeyPair} to work from. It only needs a public
* key.
* @return the base name of the key files.
*/
public static String keyFileBase(DnsKeyPair pair)
{
DNSKEYRecord keyrec = pair.getDNSKEYRecord();
if (keyrec == null) return null;
return getKeyFileBase(keyrec.getName(),
keyrec.getAlgorithm(),
keyrec.getFootprint());
}
/** @return a {@link java.io.File} object representing the BIND9
* public key file. */
public static File getPublicKeyFile(DnsKeyPair pair, File inDirectory)
{
String keyfilebase = keyFileBase(pair);
if (keyfilebase == null) return null;
return new File(inDirectory, keyfilebase + ".key");
}
/** @return a {@link java.io.File} object representing the BIND9
* private key file */
public static File getPrivateKeyFile(DnsKeyPair pair, File inDirectory)
{
String keyfilebase = keyFileBase(pair);
if (keyfilebase == null) return null;
return new File(inDirectory, keyfilebase + ".private");
}
/** Given a the contents of a BIND9 private key file, convert it
* into a native {@link java.security.PrivateKey} object.
* @param privateKeyString the contents of a BIND9 key file in
* string form.
* @return a {@link java.security.PrivateKey}
*/
public static PrivateKey convertPrivateKeyString(String privateKeyString)
{
if (privateKeyString == null) return null;
// FIXME: should this swallow exceptions or actually propagate
// them?
try
{
DnsKeyConverter conv = new DnsKeyConverter();
return conv.parsePrivateKeyString(privateKeyString);
}
catch (IOException e)
{
e.printStackTrace();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
return null;
}
/** Given a native private key, convert it into a BIND9 private key
* file format.
* @param priv the private key to convert.
* @param pub the private key's corresponding public key. Some
* algorithms require information from both.
* @return a string containing the contents of a BIND9 private key
* file.
*/
public static String convertPrivateKey(PrivateKey priv, PublicKey pub,
int alg)
{
if (priv != null)
{
// debug
// System.out.println("converting from privatekey to bind9 string");
DnsKeyConverter keyconv = new DnsKeyConverter();
String priv_string
= keyconv.generatePrivateKeyString(priv, pub, alg);
return priv_string;
}
return null;
}
/** Convert the KEY record to the exact string format that the
* dnssec-* routines need. Currently, the DNSJAVA package uses a
* multiline mode for its record formatting. The BIND9 tools
* require everything on a single line. */
private static String DNSKEYtoString(DNSKEYRecord rec)
{
StringBuffer buf = new StringBuffer();
buf.append(rec.getName());
buf.append(" IN DNSKEY ");
buf.append(rec.getFlags() & 0xFFFF);
buf.append(" ");
buf.append(rec.getProtocol());
buf.append(" ");
buf.append(rec.getAlgorithm());
buf.append(" ");
buf.append(base64.toString(rec.getKey()));
return buf.toString();
}
/** This routine will write out the BIND9 dnssec-* tool compatible
* files.
*
* @param baseFileName use this base file name. If null, the
* standard BIND9 base file name will be computed.
* @param pair the keypair in question.
* @param inDirectory the directory to write to (may be null).
* @throws IOException if there is a problem writing the files.
*/
public static void writeKeyFiles(String baseFileName, DnsKeyPair pair,
File inDirectory)
throws IOException
{
DNSKEYRecord pub = pair.getDNSKEYRecord();
String priv = pair.getPrivateKeyString();
if (priv == null)
{
priv = convertPrivateKey(pair.getPrivate(), pair.getPublic(),
pair.getDNSKEYAlgorithm());
}
if (pub == null || priv == null) return;
// Write the public key file
File pubkeyfile = new File(inDirectory, baseFileName + ".key");
PrintWriter out
= new PrintWriter(new FileWriter(pubkeyfile));
out.println(DNSKEYtoString(pub));
out.close();
// Write the private key file
File privkeyfile = new File(inDirectory, baseFileName + ".private");
out = new PrintWriter(new FileWriter(privkeyfile));
out.print(priv);
out.close();
}
/** This routine will write out the BIND9 dnssec-* tool compatible
* files to the standard file names.
*
* @param pair the key pair in question.
* @param inDirectory the directory to write to (may be null).
*/
public static void writeKeyFiles(DnsKeyPair pair, File inDirectory)
throws IOException
{
String base = keyFileBase(pair);
writeKeyFiles(base, pair, inDirectory);
}
}

View File

@ -0,0 +1,66 @@
// $Id: ByteArrayComparator.java,v 1.2 2004/02/25 20:46:14 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.verisignlabs.dnssec.security;
import java.util.*;
/** This class implements a basic comparitor for byte arrays. It is
* primarily useful for comparing RDATA portions of DNS records in
* doing DNSSEC canonical ordering.
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.2 $
*/
public class ByteArrayComparator implements Comparator
{
private int mOffset = 0;
private boolean mDebug = false;
public ByteArrayComparator()
{}
public ByteArrayComparator(int offset, boolean debug)
{
mOffset = offset;
mDebug = debug;
}
public int compare(Object o1, Object o2) throws ClassCastException
{
byte[] b1 = (byte[]) o1;
byte[] b2 = (byte[]) o2;
for (int i = mOffset; i < b1.length && i < b2.length; i++)
{
if (b1[i] != b2[i])
{
if (mDebug)
{
System.out.println("offset " + i + " differs (this is " +
(i - mOffset) +" bytes in from our offset.)");
}
return (b1[i] & 0xFF) - (b2[i] & 0xFF);
}
}
return b1.length - b2.length;
}
}

View File

@ -0,0 +1,471 @@
// $Id: DnsKeyConverter.java,v 1.4 2004/02/23 15:06:15 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.verisignlabs.dnssec.security;
import java.io.*;
import java.util.StringTokenizer;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import javax.crypto.spec.DHPrivateKeySpec;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import java.security.interfaces.*;
import org.xbill.DNS.*;
import org.xbill.DNS.security.KEYConverter;
import org.xbill.DNS.utils.base64;
/** This class handles conversions between JCA key formats and DNSSEC
* and BIND9 key formats.
*
* @author David Blacka (original)
* @author $Author: davidb $ (latest)
* @version $Revision: 1.4 $
*/
public class DnsKeyConverter
{
private KeyFactory mRSAKeyFactory;
private KeyFactory mDSAKeyFactory;
private KeyFactory mDHKeyFactory;
public DnsKeyConverter()
{
}
/** Given a DNS KEY record, return the JCA public key */
public PublicKey parseDNSKEYRecord(DNSKEYRecord pKeyRecord)
{
if (pKeyRecord.getKey() == null) return null;
return KEYConverter.parseRecord(pKeyRecord);
}
/** Given a JCA public key and the ancillary data, generate a DNSKEY
* record. */
public DNSKEYRecord generateDNSKEYRecord(Name name,
int dclass,
long ttl,
int flags,
int alg,
PublicKey key)
{
// FIXME: currenty org.xbill.DNS.security.KEYConverter will only
// convert to KEYRecords, and even then, assume that an RSA
// PublicKey means alg 1.
KEYRecord kr = KEYConverter.buildRecord(name, dclass, ttl, flags,
KEYRecord.PROTOCOL_DNSSEC, key);
return new DNSKEYRecord(name, dclass, ttl, flags,
DNSKEYRecord.Protocol.DNSSEC, alg,
kr.getKey());
}
// Private Key Specific Parsing routines
/** Convert a PKCS#8 encoded private key into a PrivateKey
* object. */
public PrivateKey convertEncodedPrivateKey(byte[] key, int algorithm)
{
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key);
try
{
switch (algorithm)
{
case DNSSEC.RSAMD5:
case DNSSEC.RSASHA1:
return mRSAKeyFactory.generatePrivate(spec);
case DNSSEC.DSA:
return mDSAKeyFactory.generatePrivate(spec);
}
}
catch (GeneralSecurityException e)
{
}
return null;
}
/** @return a JCA private key, given a BIND9-style textual
* encoding */
public PrivateKey parsePrivateKeyString(String key)
throws IOException, NoSuchAlgorithmException
{
StringTokenizer lines = new StringTokenizer(key, "\n");
while (lines.hasMoreTokens())
{
String line = lines.nextToken();
if (line == null) continue;
if (line.startsWith("#")) continue;
String val = value(line);
if (val == null) continue;
if (line.startsWith("Private-key-format: "))
{
if (! val.equals("v1.2"))
{
throw new IOException("unsupported private key format: " + val);
}
}
else if (line.startsWith("Algorithm: "))
{
if (val.startsWith("1 ")) return parsePrivateRSA(lines);
if (val.startsWith("5 ")) return parsePrivateRSA(lines);
if (val.startsWith("2 ")) return parsePrivateDH(lines);
if (val.startsWith("3 ")) return parsePrivateDSA(lines);
throw new IOException("unsupported private key algorithm: " + val);
}
}
return null;
}
/** @return the value part of an "attribute:value" pair. The value
* is trimmed. */
private String value(String av)
{
if (av == null) return null;
int pos = av.indexOf(':');
if (pos < 0) return av;
if (pos >= av.length()) return null;
return av.substring(pos + 1).trim();
}
/** prints the bytes of an original byte array and the BigInteger
* copy */
private void printBigIntCompare(byte[] orig, BigInteger copy)
{
byte[] copy_bytes = copy.toByteArray();
for (int i = 0; i < 10 && i < orig.length; i++) {
System.err.print((int) orig[i] & 0xFF);
System.err.print(" ");
}
System.err.println();
for (int i = 0; i < 10 && i < copy_bytes.length; i++) {
System.err.print((int) copy_bytes[i] & 0xFF);
System.err.print(" ");
}
System.err.println();
}
/** Given the rest of the RSA BIND9 string format private key, parse
* and translate into a JCA private key
*
* @throws NoSuchAlgorithmException if the RSA algorithm is not
* available. */
private PrivateKey parsePrivateRSA(StringTokenizer lines)
throws NoSuchAlgorithmException
{
BigInteger modulus = null;
BigInteger public_exponent = null;
BigInteger private_exponent = null;
BigInteger prime_p = null;
BigInteger prime_q = null;
BigInteger prime_p_exponent = null;
BigInteger prime_q_exponent = null;
BigInteger coefficient = 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("Modulus: ")) {
modulus = new BigInteger(1, data);
// printBigIntCompare(data, modulus);
} else if (line.startsWith("PublicExponent: ")) {
public_exponent = new BigInteger(1, data);
// printBigIntCompare(data, public_exponent);
} else if (line.startsWith("PrivateExponent: ")) {
private_exponent = new BigInteger(1, data);
// printBigIntCompare(data, private_exponent);
} else if (line.startsWith("Prime1: ")) {
prime_p = new BigInteger(1, data);
// printBigIntCompare(data, prime_p);
} else if (line.startsWith("Prime2: ")) {
prime_q = new BigInteger(1, data);
// printBigIntCompare(data, prime_q);
} else if (line.startsWith("Exponent1: ")) {
prime_p_exponent = new BigInteger(1, data);
} else if (line.startsWith("Exponent2: ")) {
prime_q_exponent = new BigInteger(1, data);
} else if (line.startsWith("Coefficient: ")) {
coefficient = new BigInteger(1, data);
}
}
try
{
KeySpec spec = new RSAPrivateCrtKeySpec(modulus, public_exponent,
private_exponent, prime_p,
prime_q, prime_p_exponent,
prime_q_exponent, coefficient);
if (mRSAKeyFactory == null)
{
mRSAKeyFactory = KeyFactory.getInstance("RSA");
}
return mRSAKeyFactory.generatePrivate(spec);
}
catch (InvalidKeySpecException e)
{
e.printStackTrace();
return null;
}
}
/** Given the remaining lines in a BIND9 style DH private key, parse
* the key info and translate it into a JCA private key.
*
* @throws NoSuchAlgorithmException if the DH algorithm is not
* available. */
private PrivateKey parsePrivateDH(StringTokenizer lines)
throws NoSuchAlgorithmException
{
BigInteger p = null;
BigInteger x = null;
BigInteger g = 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("Prime(p): ")) {
p = new BigInteger(1, data);
} else if (line.startsWith("Generator(g): ")) {
g = new BigInteger(1, data);
} else if (line.startsWith("Private_value(x): ")) {
x = new BigInteger(1, data);
}
}
try
{
KeySpec spec = new DHPrivateKeySpec(x, p, g);
if (mDHKeyFactory == null)
{
mDHKeyFactory = KeyFactory.getInstance("DH");
}
return mDHKeyFactory.generatePrivate(spec);
}
catch (InvalidKeySpecException e)
{
e.printStackTrace();
return null;
}
}
/** Given the remaining lines in a BIND9 style DSA private key,
* parse the key info and translate it into a JCA private key.
*
* @throws NoSuchAlgorithmException if the DSA algorithm is not
* available. */
private PrivateKey parsePrivateDSA(StringTokenizer lines)
throws NoSuchAlgorithmException
{
BigInteger p = null;
BigInteger q = null;
BigInteger g = null;
BigInteger x = 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("Prime(p): ")) {
p = new BigInteger(1, data);
} else if (line.startsWith("Subprime(q): ")) {
q = new BigInteger(1, data);
} else if (line.startsWith("Base(g): ")) {
g = new BigInteger(1, data);
} else if (line.startsWith("Private_value(x): ")) {
x = new BigInteger(1, data);
}
}
try
{
KeySpec spec = new DSAPrivateKeySpec(x, p, q, g);
if (mDSAKeyFactory == null)
{
mDSAKeyFactory = KeyFactory.getInstance("DSA");
}
return mDSAKeyFactory.generatePrivate(spec);
}
catch (InvalidKeySpecException e)
{
e.printStackTrace();
return null;
}
}
/** Given a private key and public key, generate the BIND9 style
* private key format. */
public String generatePrivateKeyString(PrivateKey priv, PublicKey pub,
int alg)
{
if (priv instanceof RSAPrivateCrtKey)
{
return generatePrivateRSA((RSAPrivateCrtKey) priv, alg);
}
else if (priv instanceof DSAPrivateKey &&
pub instanceof DSAPublicKey)
{
return generatePrivateDSA((DSAPrivateKey) priv, (DSAPublicKey) pub);
}
else if (priv instanceof DHPrivateKey &&
pub instanceof DHPublicKey)
{
return generatePrivateDH((DHPrivateKey) priv, (DHPublicKey) pub);
}
return null;
}
/** Convert from 'unsigned' big integer to original 'signed format'
* in Base64 */
private String b64BigInt(BigInteger i)
{
byte[] orig_bytes = i.toByteArray();
if (orig_bytes[0] != 0 || orig_bytes.length == 1)
{
return base64.toString(orig_bytes);
}
byte[] signed_bytes = new byte[orig_bytes.length - 1];
System.arraycopy(orig_bytes, 1, signed_bytes, 0, signed_bytes.length);
return base64.toString(signed_bytes);
}
/** Given a RSA private key (in Crt format), return the BIND9-style
* text encoding. */
private String generatePrivateRSA(RSAPrivateCrtKey key, int algorithm)
{
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
out.println("Private-key-format: v1.2");
if (algorithm == DNSSEC.RSAMD5)
{
out.println("Algorithm: 1 (RSAMD5)");
}
else
{
out.println("Algorithm: 5 (RSASHA1)");
}
out.print("Modulus: ");
out.println(b64BigInt(key.getModulus()));
out.print("PublicExponent: ");
out.println(b64BigInt(key.getPublicExponent()));
out.print("PrivateExponent: ");
out.println(b64BigInt(key.getPrivateExponent()));
out.print("Prime1: ");
out.println(b64BigInt(key.getPrimeP()));
out.print("Prime2: ");
out.println(b64BigInt(key.getPrimeQ()));
out.print("Exponent1: ");
out.println(b64BigInt(key.getPrimeExponentP()));
out.print("Exponent2: ");
out.println(b64BigInt(key.getPrimeExponentQ()));
out.print("Coefficient: ");
out.println(b64BigInt(key.getCrtCoefficient()));
return sw.toString();
}
/** Given a DH key pair, return the BIND9-style text encoding */
private String generatePrivateDH(DHPrivateKey key, DHPublicKey pub)
{
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
DHParameterSpec p = key.getParams();
out.println("Private-key-format: v1.2");
out.println("Algorithm: 2 (DH)");
out.print("Prime(p): ");
out.println(b64BigInt(p.getP()));
out.print("Generator(g): ");
out.println(b64BigInt(p.getG()));
out.print("Private_value(x): ");
out.println(b64BigInt(key.getX()));
out.print("Public_value(y): ");
out.println(b64BigInt(pub.getY()));
return sw.toString();
}
/** Given a DSA key pair, return the BIND9-style text encoding */
private String generatePrivateDSA(DSAPrivateKey key, DSAPublicKey pub)
{
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
DSAParams p = key.getParams();
out.println("Private-key-format: v1.2");
out.println("Algorithm: 3 (DSA)");
out.print("Prime(p): ");
out.println(b64BigInt(p.getP()));
out.print("Subprime(q): ");
out.println(b64BigInt(p.getQ()));
out.print("Base(g): ");
out.println(b64BigInt(p.getG()));
out.print("Private_value(x): ");
out.println(b64BigInt(key.getX()));
out.print("Public_value(y): ");
out.println(b64BigInt(pub.getY()));
return sw.toString();
}
}

View File

@ -0,0 +1,356 @@
// $Id: DnsKeyPair.java,v 1.3 2004/01/16 21:07:09 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.verisignlabs.dnssec.security;
import java.security.*;
import java.security.interfaces.*;
import org.xbill.DNS.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** This class forms the basis for representing public/private key
* pairs in a DNSSEC context. It is possible to get a JCA public and
* private key from this object, as well as a KEYRecord encoding of
* the public key. This class is implemented as a UNION of all the
* functionality needed for handing native java, BIND, and possibly
* other underlying KEY engines.
*
* JCA == Java Cryptography Architecture.
*
* @author David Blacka (orig)
* @author $Author: davidb $ (latest)
* @version $Revision: 1.3 $
*/
// FIXME: this class is not a generic DnsKeyPair at all. It is really
// a JCEDnsKeyPair. We probably need to reexamine the class design here.
// NOTE: this class is designed to do "lazy" evaluation of it's
// various cached objects and format conversions, so methods should
// avoid direct access to the member variables.
public class DnsKeyPair
{
/** This is the real (base) encoding of the public key. */
protected DNSKEYRecord mPublicKeyRecord;
/** This is a precalcuated cache of the KEYRecord converted into a
* JCA public key. */
private PublicKey mPublicKey;
/** The private key in Base64 encoded format. This version is
* presumed to be opaque, so no attempts will be made to convert it
* to a JCA private key. */
protected String mPrivateKeyString;
/** The private key in JCA format. This is the base encoding for
* instances were JCA private keys are used. */
protected PrivateKey mPrivateKey;
/** The local key converter. */
protected DnsKeyConverter mKeyConverter;
/** a cached Signature used for signing (initialized with the
* private key) */
protected Signature mSigner;
/** a caches Signature used for verifying (intialized with the
* public key) */
protected Signature mVerifier;
private Log log;
public DnsKeyPair()
{
log = LogFactory.getLog(this.getClass());
}
public DnsKeyPair(DNSKEYRecord keyRecord, PrivateKey privateKey)
{
this();
setDNSKEYRecord(keyRecord);
setPrivate(privateKey);
}
public DnsKeyPair(DNSKEYRecord keyRecord, String privateKeyString)
{
this();
setDNSKEYRecord(keyRecord);
setPrivateKeyString(privateKeyString);
}
public DnsKeyPair(Name keyName, int algorithm, PublicKey publicKey,
PrivateKey privateKey)
{
this();
DnsKeyConverter conv = new DnsKeyConverter();
DNSKEYRecord keyrec = conv.generateDNSKEYRecord(keyName, DClass.IN, 0, 0,
algorithm, publicKey);
setDNSKEYRecord(keyrec);
setPrivate(privateKey);
}
public DnsKeyPair(DnsKeyPair pair)
{
this();
setDNSKEYRecord(pair.getDNSKEYRecord());
setPrivate(pair.getPrivate());
setPrivateKeyString(pair.getPrivateKeyString());
}
/** @return cached DnsKeyConverter object. */
protected DnsKeyConverter getKeyConverter()
{
if (mKeyConverter == null)
{
mKeyConverter = new DnsKeyConverter();
}
return mKeyConverter;
}
/** @return the appropriate Signature object for this keypair. */
protected Signature getSignature()
{
Signature s = null;
// First try and deduce the algorithm from the KEYRecord (which
// will be specific), then try and deduce it from the private key.
// We should have one or the other.
try
{
switch (getDNSKEYAlgorithm())
{
case DNSSEC.RSAMD5:
s = Signature.getInstance("MD5withRSA");
break;
case DNSSEC.DSA:
s = Signature.getInstance("SHA1withDSA");
break;
case DNSSEC.RSASHA1:
s = Signature.getInstance("SHA1withRSA");
break;
case -1:
s = null;
break;
}
}
catch (NoSuchAlgorithmException e)
{
log.error("error getting Signature object", e);
}
return s;
}
/** @return the public key, translated from the KEYRecord, if
* necessary. */
public PublicKey getPublic()
{
if (mPublicKey == null && getDNSKEYRecord() != null)
{
DnsKeyConverter conv = getKeyConverter();
setPublic(conv.parseDNSKEYRecord(getDNSKEYRecord()));
}
return mPublicKey;
}
/** sets the public key. This method is generally not used
* directly. */
protected void setPublic(PublicKey k)
{
mPublicKey = k;
}
/** @return the private key. */
public PrivateKey getPrivate()
{
// attempt to convert the private key string format into a JCA
// private key.
if (mPrivateKey == null && mPrivateKeyString != null)
{
mPrivateKey = BINDKeyUtils.convertPrivateKeyString(mPrivateKeyString);
}
return mPrivateKey;
}
/** sets the private key */
public void setPrivate(PrivateKey k)
{
mPrivateKey = k;
}
/** @return the opaque private key string, null if one doesn't
* exist. */
public String getPrivateKeyString()
{
if (mPrivateKeyString == null && mPrivateKey != null)
{
PublicKey pub = getPublic();
mPrivateKeyString = BINDKeyUtils.convertPrivateKey(mPrivateKey, pub,
getDNSKEYAlgorithm());
}
return mPrivateKeyString;
}
/** sets the opaque private key string. */
public void setPrivateKeyString(String p)
{
mPrivateKeyString = p;
}
/** @return the private key in an encoded form (normally PKCS#8). */
public byte[] getEncodedPrivate()
{
PrivateKey priv = getPrivate();
if (priv != null) return priv.getEncoded();
return null;
}
/** Sets the private key from the encoded form (PKCS#8). This
* routine requires that the public key already be assigned.
* Currently it can only handle DSA and RSA keys. */
public void setEncodedPrivate(byte[] encoded)
{
int alg = getDNSKEYAlgorithm();
if (alg >= 0)
{
DnsKeyConverter conv = getKeyConverter();
setPrivate(conv.convertEncodedPrivateKey(encoded, alg));
}
}
/** @return the public DNSKEY record */
public DNSKEYRecord getDNSKEYRecord()
{
return mPublicKeyRecord;
}
/** @return a Signature object initialized for signing, or null if
* this key pair does not have a valid private key. */
public Signature getSigner()
{
if (mSigner == null)
{
mSigner = getSignature();
PrivateKey priv = getPrivate();
if (mSigner != null && priv != null)
{
try
{
mSigner.initSign(priv);
}
catch (InvalidKeyException e)
{
log.error("Signature error", e);
}
}
else
{
// do not return an unitialized signer.
return null;
}
}
return mSigner;
}
/** @return a Signature object initialized for verifying, or null if
* this key pair does not have a valid public key. */
public Signature getVerifier()
{
if (mVerifier == null)
{
mVerifier = getSignature();
PublicKey pk = getPublic();
if (mVerifier != null && pk != null)
{
try
{
mVerifier.initVerify(pk);
}
catch (InvalidKeyException e) {}
}
else
{
// do not return an unitialized verifier
return null;
}
}
return mVerifier;
}
/** sets the public key record */
public void setDNSKEYRecord(DNSKEYRecord r)
{
mPublicKeyRecord = r;
// force the conversion to PublicKey:
mPublicKey = null;
}
public Name getDNSKEYName()
{
DNSKEYRecord kr = getDNSKEYRecord();
if (kr != null) return kr.getName();
return null;
}
public int getDNSKEYAlgorithm()
{
DNSKEYRecord kr = getDNSKEYRecord();
if (kr != null) return kr.getAlgorithm();
PublicKey pk = getPublic();
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;
}
PrivateKey priv = getPrivate();
if (priv != null)
{
if (priv instanceof RSAPrivateKey) return DNSSEC.RSASHA1;
if (priv instanceof DSAPrivateKey) return DNSSEC.DSA;
}
return -1;
}
public int getDNSKEYFootprint()
{
DNSKEYRecord kr = getDNSKEYRecord();
if (kr != null) return kr.getFootprint();
return -1;
}
}

View File

@ -0,0 +1,321 @@
// $Id: DnsSecVerifier.java,v 1.5 2004/02/25 20:46:14 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.security;
import java.util.*;
import java.io.*;
import java.security.*;
import org.xbill.DNS.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** A class for performing basic DNSSEC verification. The DNSJAVA
* package contains a similar class. This differs (for the moment,
* anyway) by allowing timing "fudge" factors and logging more
* specifically why an RRset did not validate.
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.5 $
*/
public class DnsSecVerifier implements Verifier
{
private class TrustedKeyStore
{
// for now, this is implemented as a hashtable of lists of
// DnsKeyPair objects (obviously, all of them will not have
// private keys).
private HashMap mKeyMap;
public TrustedKeyStore()
{
mKeyMap = new HashMap();
}
public void add(DnsKeyPair pair)
{
String n = pair.getDNSKEYName().toString().toLowerCase();
List l = (List) mKeyMap.get(n);
if (l == null)
{
l = new ArrayList();
mKeyMap.put(n, l);
}
l.add(pair);
}
public void add(DNSKEYRecord keyrec)
{
DnsKeyPair pair = new DnsKeyPair(keyrec, (PrivateKey) null);
add(pair);
}
public void add(Name name, int algorithm, PublicKey key)
{
DnsKeyPair pair = new DnsKeyPair(name, algorithm, key, null);
add(pair);
}
public DnsKeyPair find(Name name, int algorithm, int keyid)
{
String n = name.toString().toLowerCase();
List l = (List) mKeyMap.get(n);
if (l == null) return null;
// FIXME: this algorithm assumes that name+alg+footprint is
// unique, which isn't necessarily true.
for (Iterator i = l.iterator(); i.hasNext(); )
{
DnsKeyPair p = (DnsKeyPair) i.next();
if (p.getDNSKEYAlgorithm() == algorithm &&
p.getDNSKEYFootprint() == keyid)
{
return p;
}
}
return null;
}
}
private TrustedKeyStore mKeyStore;
private int mStartFudge = 0;
private int mExpireFudge = 0;
private boolean mVerifyAllSigs = false;
private Log log;
public DnsSecVerifier()
{
log = LogFactory.getLog(this.getClass());
mKeyStore = new TrustedKeyStore();
}
public void addTrustedKey(DNSKEYRecord keyrec)
{
mKeyStore.add(keyrec);
}
public void addTrustedKey(DnsKeyPair pair)
{
mKeyStore.add(pair);
}
public void addTrustedKey(Name name, int algorithm, PublicKey key)
{
mKeyStore.add(name, algorithm, key);
}
public void addTrustedKey(Name name, PublicKey key)
{
mKeyStore.add(name, 0, key);
}
public void setExpireFudge(int fudge)
{
mExpireFudge = fudge;
}
public void setStartFudge(int fudge)
{
mStartFudge = fudge;
}
public void setVerifyAllSigs(boolean v)
{
mVerifyAllSigs = v;
}
private DnsKeyPair findCachedKey(Cache cache, 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 i = keysets[0].rrs(); i.hasNext(); )
{
Object o = i.next();
if (! (o instanceof DNSKEYRecord)) continue;
DNSKEYRecord keyrec = (DNSKEYRecord) o;
if (keyrec.getAlgorithm() == algorithm &&
keyrec.getFootprint() == footprint)
{
return new DnsKeyPair(keyrec, (PrivateKey) null);
}
}
return null;
}
private DnsKeyPair findKey(Cache cache, Name name, int algorithm,
int footprint)
{
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)
{
if (rrset == null || sigrec == null) return DNSSEC.Failed;
if (! rrset.getName().equals(sigrec.getName()))
{
log.info("Signature name does not match RRset name");
return DNSSEC.Failed;
}
if (rrset.getType() != sigrec.getTypeCovered())
{
log.info("Signature type does not match RRset type");
}
Date now = new Date();
Date start = sigrec.getTimeSigned();
Date expire = sigrec.getExpire();
if (mStartFudge >= 0)
{
if (mStartFudge > 0)
{
start = new Date(start.getTime() - ((long) mStartFudge * 1000));
}
if (now.before(start))
{
log.info("Signature is not yet valid");
return DNSSEC.Failed;
}
}
if (mExpireFudge >= 0)
{
if (mExpireFudge > 0)
{
expire = new Date(expire.getTime() + ((long) mExpireFudge * 1000));
}
if (now.after(expire))
{
log.info("Signature has expired (now = " + now +
", sig expires = " + expire);
return DNSSEC.Failed;
}
}
return DNSSEC.Secure;
}
/** Verify an RRset against a particular signature.
*
* @return DNSSEC.Secure if the signature verfied, 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). */
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache)
{
byte result = validateSignature(rrset, sigrec);
if (result != DNSSEC.Secure) return result;
DnsKeyPair keypair = findKey(cache, sigrec.getSigner(),
sigrec.getAlgorithm(),
sigrec.getFootprint());
if (keypair == null)
{
log.info("could not find appropriate key");
return DNSSEC.Insecure;
}
try
{
byte[] data = SignUtils.generateSigData(rrset, sigrec);
Signature signer = keypair.getVerifier();
signer.update(data);
byte[] sig = sigrec.getSignature();
if (sigrec.getAlgorithm() == DNSSEC.DSA)
{
sig = SignUtils.convertDSASignature(sig);
}
if (!signer.verify(sig))
{
log.info("Signature failed to verify cryptographically");
return DNSSEC.Failed;
}
return DNSSEC.Secure;
}
catch (IOException e)
{
log.error("I/O error", e);
}
catch (GeneralSecurityException e)
{
log.error("Security error", e);
}
log.debug("Signature failed to verify due to exception");
return DNSSEC.Insecure;
}
/** 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. */
public int verify(RRset rrset, Cache cache)
{
int result = mVerifyAllSigs ? DNSSEC.Secure: DNSSEC.Insecure;
Iterator i = rrset.sigs();
if ( ! i.hasNext())
{
log.info("RRset failed to verify due to lack of signatures");
return DNSSEC.Insecure;
}
while (i.hasNext())
{
RRSIGRecord sigrec = (RRSIGRecord) i.next();
byte res = verifySignature(rrset, sigrec, cache);
if (!mVerifyAllSigs && res == DNSSEC.Secure) return res;
if (!mVerifyAllSigs && res < result) result = res;
if (mVerifyAllSigs && res != DNSSEC.Secure && res < result)
{
result = res;
}
}
return result;
}
}

View File

@ -0,0 +1,373 @@
// $Id: JCEDnsSecSigner.java,v 1.3 2004/02/25 20:46:14 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.security;
import java.util.*;
import java.io.*;
import java.security.*;
import java.security.interfaces.*;
import org.xbill.DNS.*;
/** This class contains routines for signing DNS zones.
*
* In particular, it contains both an ability to sign an individual
* RRset and the ability to sign and entire zone. It primarily glues
* together the more basic primitives found in {@link SignUtils}.
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.3 $
*/
public class JCEDnsSecSigner
{
private DnsKeyConverter mKeyConverter;
private KeyPairGenerator mRSAKeyGenerator;
private KeyPairGenerator mDSAKeyGenerator;
/** Cryptographically generate a new DNSSEC key.
*
* @param owner the KEY RR's owner name.
* @param ttl the KEY RR's TTL.
* @param dclass the KEY RR's DNS class.
* @param algorithm the DNSSEC algorithm (RSAMD5, RSASHA1, or DSA).
* @param flags any flags for the KEY RR.
* @param keysize the size of the key to generate.
* @return a DnsKeyPair with the public and private keys populated.
*/
public DnsKeyPair generateKey(Name owner,
long ttl,
int dclass,
int algorithm,
int flags,
int keysize)
throws IOException, NoSuchAlgorithmException
{
KeyPair pair;
if (ttl < 0) ttl = 86400; // set to a reasonable default.
switch (algorithm)
{
case DNSSEC.RSAMD5:
case DNSSEC.RSASHA1:
if (mRSAKeyGenerator == null)
{
mRSAKeyGenerator = KeyPairGenerator.getInstance("RSA");
}
mRSAKeyGenerator.initialize(keysize);
pair = mRSAKeyGenerator.generateKeyPair();
break;
case DNSSEC.DSA:
if (mDSAKeyGenerator == null)
{
mDSAKeyGenerator = KeyPairGenerator.getInstance("DSA");
}
mDSAKeyGenerator.initialize(keysize);
pair = mDSAKeyGenerator.generateKeyPair();
break;
default:
throw new NoSuchAlgorithmException("Alg " + algorithm);
}
if (mKeyConverter == null)
{
mKeyConverter = new DnsKeyConverter();
}
DNSKEYRecord keyrec = mKeyConverter.generateDNSKEYRecord(owner,
dclass,
ttl,
flags,
algorithm,
pair.getPublic());
DnsKeyPair dnspair = new DnsKeyPair();
dnspair.setDNSKEYRecord(keyrec);
dnspair.setPublic(pair.getPublic()); // keep from conv. the keyrec back.
dnspair.setPrivate(pair.getPrivate());
return dnspair;
}
/** Sign an RRset.
*
* @param rrset the RRset to sign -- any existing signatures are ignored.
* @param keypars a list of DnsKeyPair objects containing private keys.
* @param start the inception time for the resulting RRSIG records.
* @param expire the expiration time for the resulting RRSIG records.
* @return a list of RRSIGRecord objects.
*/
public List signRRset(RRset rrset, List keypairs, Date start, Date expire)
throws IOException, GeneralSecurityException
{
if (rrset == null || keypairs == null) return null;
// default start to now, expire to start + 1 second.
if (start == null) start = new Date();
if (expire == null) expire = new Date(start.getTime() + 1000L);
if (keypairs.size() == 0) return null;
// first, pre-calculate the rrset bytes.
byte[] rrset_data = SignUtils.generateCanonicalRRsetData(rrset);
ArrayList sigs = new ArrayList(keypairs.size());
// for each keypair, sign the rrset.
for (Iterator i = keypairs.iterator(); i.hasNext(); )
{
DnsKeyPair pair = (DnsKeyPair) i.next();
DNSKEYRecord keyrec = pair.getDNSKEYRecord();
if (keyrec == null) continue;
RRSIGRecord presig = SignUtils.generatePreRRSIG(rrset, keyrec, start,
expire, rrset.getTTL());
byte[] sign_data = SignUtils.generateSigData(rrset_data, presig);
Signature signer = pair.getSigner();
if (signer == null)
{
// debug
System.out.println("missing private key that goes with:\n" +
pair.getDNSKEYRecord());
throw new GeneralSecurityException
("cannot sign without a valid Signer " +
"(probably missing private key)");
}
// sign the data.
signer.update(sign_data);
byte[] sig = signer.sign();
// Convert to RFC 2536 format, if necessary.
if (pair.getDNSKEYAlgorithm() == DNSSEC.DSA)
{
sig = SignUtils.convertDSASignature
(((DSAPublicKey)pair.getPublic()).getParams(), sig);
}
RRSIGRecord sigrec = SignUtils.generateRRSIG(sig, presig);
sigs.add(sigrec);
}
return sigs;
}
/** Create a completely self-signed KEY RRset.
*
* @param keypairs the public & private keypairs to use in the keyset.
* @param start the RRSIG inception time.
* @param expire the RRSIG expiration time.
* @return a signed RRset.
*/
public RRset makeKeySet(List keypairs, Date start, Date expire)
throws IOException, GeneralSecurityException
{
// Generate a KEY RR set to sign.
RRset keyset = new RRset();
for (Iterator i = keypairs.iterator(); i.hasNext(); )
{
DnsKeyPair pair = (DnsKeyPair) i.next();
keyset.addRR(pair.getDNSKEYRecord());
}
List records = signRRset(keyset, keypairs, start, expire);
for (Iterator i = records.iterator(); i.hasNext(); )
{
keyset.addRR((Record) i.next());
}
return keyset;
}
/** Conditionally sign an RRset and add it to the toList.
*
* @param toList the list to which we are adding the processed RRsets.
* @param zonename the zone apex name.
* @param rrset the rrset under consideration.
* @param keysigningkeypairs the List of KSKs..
* @param zonekeypairs the List of zone keys.
* @param start the RRSIG inception time.
* @param expire the RRSIG expiration time.
* @param fullySignKeyset if true, sign the zone apex keyset with
* both KSKs and ZSKs.
* @param last_cut the name of the last delegation point encountered.
* @return the name of the new last_cut.
*/
private Name addRRset(List toList, Name zonename, RRset rrset,
List keysigningkeypairs, List zonekeypairs,
Date start, Date expire, boolean fullySignKeyset,
Name last_cut)
throws IOException, GeneralSecurityException
{
// add the records themselves
for (Iterator i = rrset.rrs(); i.hasNext(); )
{
toList.add(i.next());
}
int type = SignUtils.recordSecType(zonename, rrset.getName(),
rrset.getType(), last_cut);
// we don't sign non-normal sets (delegations, glue, invalid).
// we also don't sign the zone key set unless we've been asked.
if (type == SignUtils.RR_DELEGATION)
{
return rrset.getName();
}
if (type == SignUtils.RR_GLUE || type == SignUtils.RR_INVALID)
{
return last_cut;
}
// check for the zone apex keyset.
if (rrset.getName().equals(zonename) && rrset.getType() == Type.DNSKEY)
{
// if we have key signing keys, sign the keyset with them,
// otherwise we will just sign them with the zonesigning keys.
if (keysigningkeypairs != null && keysigningkeypairs.size() > 0)
{
List sigs = signRRset(rrset, keysigningkeypairs, start, expire);
toList.addAll(sigs);
// If we aren't going to sign with all the keys, bail out now.
if (!fullySignKeyset) return last_cut;
}
}
// otherwise, we are OK to sign this set.
List sigs = signRRset(rrset, zonekeypairs, start, expire);
toList.addAll(sigs);
return last_cut;
}
/** Given a zone, sign it.
*
* @param zonename the name of the zone.
* @param records the records comprising the zone. They do not
* have to be in any particular order, as this method will order
* them as necessary.
* @param keysigningkeypairs the key pairs that are designated as
* "key signing keys".
* @param zonekeypair this key pairs that are designated as "zone
* signing keys".
* @param start the RRSIG inception time.
* @param expire the RRSIG expiration time.
* @param useOptIn generate Opt-In style NXT records. It will
* consider any insecure delegation to be unsigned. To override
* this, include the name of the insecure delegation in the
* NXTIncludeNames list.
* @param useConservativeOptIn if true, Opt-In NXT records will
* only be generated if there are insecure, unsigned delegations in
* the span. Not effect if useOptIn is false.
* @param fullySignKeyset sign the zone apex keyset with all available keys.
* @param NXTIncludeNames names that are to be included in the NXT
* chain regardless. This may be null and is only used if useOptIn
* is true.
*
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone.
*/
public List signZone(Name zonename,
List records,
List keysigningkeypairs,
List zonekeypairs,
Date start,
Date expire,
boolean useOptIn,
boolean useConservativeOptIn,
boolean fullySignKeyset,
List NSECIncludeNames)
throws IOException, GeneralSecurityException
{
// Remove any existing DNSSEC records (NSEC, RRSIG)
SignUtils.removeGeneratedRecords(zonename, records);
// Sort the zone
Collections.sort(records, new RecordComparator());
// Remove any duplicate records.
SignUtils.removeDuplicateRecords(records);
// Generate DS records
SignUtils.generateDSRecords(zonename, records);
// Generate NXT records
if (useOptIn)
{
SignUtils.generateOptInNSECRecords(zonename, records,
NSECIncludeNames,
useConservativeOptIn);
}
else
{
SignUtils.generateNSECRecords(zonename, records);
}
// Assemble into RRsets and sign.
RRset rrset = new RRset();
ArrayList signed_records = new ArrayList();
Name last_cut = null;
for (ListIterator i = records.listIterator(); i.hasNext(); )
{
Record r = (Record) i.next();
Name r_name = r.getName();
// First record
if (rrset.getName() == null)
{
rrset.addRR(r);
continue;
}
// Current record is part of the current RRset.
if (rrset.getName().equals(r.getName()) &&
rrset.getDClass() == r.getDClass() &&
rrset.getType() == r.getType())
{
rrset.addRR(r);
continue;
}
// Otherwise, we have completed the RRset
// Sign the records
// add the RRset to the list of signed_records, regardless of
// whether or not we actually end up signing the set.
last_cut = addRRset(signed_records, zonename, rrset, keysigningkeypairs,
zonekeypairs, start, expire, fullySignKeyset,
last_cut);
rrset.clear();
rrset.addRR(r);
}
// add the last RR set
addRRset(signed_records, zonename, rrset, keysigningkeypairs, zonekeypairs,
start, expire, fullySignKeyset, last_cut);
return signed_records;
}
}

View File

@ -0,0 +1,91 @@
// $Id: RecordComparator.java,v 1.2 2004/01/16 17:54:48 davidb Exp $
//
// Copyright (C) 2000-2003 Network Solutions, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.security;
import java.util.*;
import org.xbill.DNS.*;
/** This class implements a comparison operator for {@link
* org.xbill.DNS.Record} objects. It imposes a canonical order
* consistent with DNSSEC. It does not put records within a RRset
* into canonical order: see {@link ByteArrayComparator}.
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.2 $ */
public class RecordComparator implements Comparator
{
public RecordComparator()
{}
/** In general, types are compared numerically. However, SOA and NS
* are ordered before the rest. */
private int compareTypes(int a, int b)
{
if (a == b) return 0;
if (a == Type.SOA) return -1;
if (b == Type.SOA) return 1;
if (a == Type.NS) return -1;
if (b == Type.NS) return 1;
if (a < b) return -1;
return 1;
}
public int compare(Object o1, Object o2)
throws ClassCastException
{
Record a = (Record) o1;
Record b = (Record) o2;
if (a == null && b == null) return 0;
if (a == null) return 1;
if (b == null) return -1;
int res = a.getName().compareTo(b.getName());
if (res != 0) return res;
int a_type = a.getType();
int b_type = b.getType();
int sig_type = 0;
if (a_type == Type.RRSIG)
{
a_type = ((RRSIGRecord) a).getTypeCovered();
sig_type = 1;
}
if (b_type == Type.RRSIG)
{
b_type = ((RRSIGRecord) b).getTypeCovered();
sig_type = -1;
}
res = compareTypes(a_type, b_type);
if (res != 0) return res;
if (sig_type != 0) return sig_type;
return 0;
}
}

View File

@ -0,0 +1,927 @@
// $Id: SignUtils.java,v 1.7 2004/03/23 17:53:57 davidb Exp $
//
// Copyright (C) 2001-2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.security;
import java.util.*;
import java.io.*;
import java.security.MessageDigest;
import java.security.interfaces.DSAParams;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import org.xbill.DNS.*;
import org.xbill.DNS.utils.base64; // debug only
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** This class contains a bunch of utility methods that are generally
* useful in signing zones.
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.7 $
*/
public class SignUtils
{
private static final int DSA_SIGNATURE_LENGTH = 20;
private static final int ASN1_INT = 0x02;
private static final int ASN1_SEQ = 0x30;
public static final int RR_NORMAL = 0;
public static final int RR_DELEGATION = 1;
public static final int RR_GLUE = 2;
public static final int RR_INVALID = 3;
private static Log log;
static {
log = LogFactory.getLog(SignUtils.class);
}
public static void setLog(Log v)
{
log = v;
}
/** Generate from some basic information a prototype SIG RR
* containing everything but the actual signature itself.
*
* @param rrset the RRset being signed.
* @param key the public KEY RR counterpart to the key being used
* to sign the RRset
* @param start the SIG inception time.
* @param expire the SIG expiration time.
* @param sig_ttl the TTL of the resulting SIG record.
* @return a prototype signature based on the RRset and key
* information. */
public static RRSIGRecord generatePreRRSIG(RRset rrset, DNSKEYRecord key,
Date start, Date expire,
long sig_ttl)
{
return new RRSIGRecord(rrset.getName(),
rrset.getDClass(),
sig_ttl,
rrset.getType(),
key.getAlgorithm(),
(int) rrset.getTTL(),
expire,
start,
key.getFootprint(),
key.getName(),
null);
}
/** Generate from some basic information a prototype SIG RR
* containing everything but the actual signature itself.
*
* @param rec the DNS record being signed (forming an entire RRset).
* @param key the public KEY RR counterpart to the key signing the
* record.
* @param start the SIG inception time.
* @param expire the SIG expiration time.
* @param sig_ttl the TTL of the result SIG record.
* @return a prototype signature based on the Record and key
* information. */
public static RRSIGRecord generatePreRRSIG(Record rec, DNSKEYRecord key,
Date start, Date expire,
long sig_ttl)
{
return new RRSIGRecord(rec.getName(),
rec.getDClass(),
sig_ttl,
rec.getType(),
key.getAlgorithm(),
rec.getTTL(),
expire,
start,
key.getFootprint(),
key.getName(),
null);
}
/** Generate the binary image of the prototype SIG RR.
*
* @param presig the SIG RR prototype.
* @return the RDATA portion of the prototype SIG record. This
* forms the first part of the data to be signed. */
private static byte[] generatePreSigRdata(RRSIGRecord presig)
throws IOException
{
// Generate the binary image;
DNSOutput image = new DNSOutput();
// precalc some things
int start_time = (int) (presig.getTimeSigned().getTime() / 1000);
int expire_time = (int) (presig.getExpire().getTime() / 1000);
Name signer = presig.getSigner();
// first write out the partial SIG record (this is the SIG RDATA
// minus the actual signature.
image.writeU16(presig.getTypeCovered());
image.writeU8(presig.getAlgorithm());
image.writeU8(presig.getLabels());
image.writeU32((int) presig.getOrigTTL());
image.writeU32(expire_time);
image.writeU32(start_time);
image.writeU16(presig.getFootprint());
image.writeByteArray(signer.toWireCanonical());
return image.toByteArray();
}
/** Calculate the canonical wire line format of the RRset.
*
* @param rrset the RRset to convert.
* @return the canonical wire line format of the rrset. This is
* the second part of data to be signed.*/
public static byte[] generateCanonicalRRsetData(RRset rrset)
throws IOException
{
DNSOutput image = new DNSOutput();
// now convert load the wire format records in the RRset into a
// list of byte arrays.
ArrayList canonical_rrs = new ArrayList();
for (Iterator i = rrset.rrs(); i.hasNext(); )
{
Record r = (Record) i.next();
byte[] wire_fmt = r.toWireCanonical();
canonical_rrs.add(wire_fmt);
}
// put the records into the correct ordering.
// Caculate the offset where the RDATA begins (we have to skip
// past the length byte)
// FIXME: currently, draft-ietf-dnsext-dnssec-records-06 has us
// sorting by length first, then bytes. This can be accomplished
// by not skipping past the RDLENGTH field, I think.
// FIXME update: I pointed this out as an error, and subsequent
// versions should correct this, setting the standard back to
// bytes, then length.
int offset = rrset.getName().toWireCanonical().length + 10;
ByteArrayComparator bac = new ByteArrayComparator(offset, false);
Collections.sort(canonical_rrs, bac);
for (Iterator i = canonical_rrs.iterator(); i.hasNext(); )
{
byte[] wire_fmt_rec = (byte[]) i.next();
image.writeByteArray(wire_fmt_rec);
}
return image.toByteArray();
}
/** Given an RRset and the prototype signature, generate the
* canonical data that is to be signed.
*
* @param rrset the RRset to be signed.
* @param presig a prototype SIG RR created using the same RRset.
* @return a block of data ready to be signed.
*/
public static byte[] generateSigData(RRset rrset, RRSIGRecord presig)
throws IOException
{
byte[] rrset_data = generateCanonicalRRsetData(rrset);
return generateSigData(rrset_data, presig);
}
/** Given an RRset and the prototype signature, generate the
* canonical data that is to be signed.
*
* @param rrset_data the RRset converted into canonical wire line
* format (as per the canonicalization rules in RFC 2535).
* @param presig the prototype signature based on the same RRset
* represented in <code>rrset_data</code>.
* @return a block of data ready to be signed.
*/
public static byte[] generateSigData(byte[] rrset_data, RRSIGRecord presig)
throws IOException
{
byte[] sig_rdata = generatePreSigRdata(presig);
ByteArrayOutputStream image
= new ByteArrayOutputStream(sig_rdata.length + rrset_data.length);
image.write(sig_rdata);
image.write(rrset_data);
return image.toByteArray();
}
/** Given the acutal signature an the prototype signature, combine
* them and return the fully formed SIGRecord.
*
* @param signature the cryptographic signature, in DNSSEC format.
* @param presig the prototype SIG RR to add the signature to.
* @return the fully formed SIG RR.
*/
public static RRSIGRecord generateRRSIG(byte[] signature, RRSIGRecord presig)
{
return new RRSIGRecord(presig.getName(),
presig.getDClass(),
presig.getTTL(),
presig.getTypeCovered(),
presig.getAlgorithm(),
presig.getOrigTTL(),
presig.getExpire(),
presig.getTimeSigned(),
presig.getFootprint(),
presig.getSigner(),
signature);
}
/** Converts from a RFC 2536 formatted DSA signature to a JCE
* (ASN.1) formatted signature.
*
* <p>ASN.1 format = ASN1_SEQ . seq_length . ASN1_INT . Rlength . R
* . ANS1_INT . Slength . S</p>
*
* The integers R and S may have a leading null byte to force the
* integer positive.
*
* @param signature the RFC 2536 formatted DSA signature.
* @return The ASN.1 formatted DSA signature.
* @throws SignatureException if there was something wrong with the
* RFC 2536 formatted signature.
**/
public static byte[] convertDSASignature(byte[] signature)
throws SignatureException
{
if (signature.length != 41)
throw new SignatureException("RFC 2536 signature not expected length.");
byte r_pad = 0;
byte s_pad = 0;
// handle initial null byte padding.
if (signature[1] < 0) r_pad++;
if (signature[21] < 0) s_pad++;
// ASN.1 length = R length + S length + (2 + 2 + 2), where each 2
// is for a ASN.1 type-length byte pair of which there are three
// (SEQ, INT, INT).
byte sig_length = (byte) (40 + r_pad + s_pad + 6);
byte sig[] = new byte[sig_length];
byte pos = 0;
sig[pos++] = ASN1_SEQ;
sig[pos++] = (byte) (sig_length - 2); // all but the SEQ type+length.
sig[pos++] = ASN1_INT;
sig[pos++] = (byte) (20 + r_pad);
// copy the value of R, leaving a null byte if necessary
if (r_pad == 1) sig[pos++] = 0;
System.arraycopy(signature, 1, sig, pos, 20);
pos += 20;
sig[pos++] = ASN1_INT;
sig[pos++] = (byte) (20 + s_pad);
// copy the value of S, leaving a null byte if necessary
if (s_pad == 1) sig[pos++] = 0;
System.arraycopy(signature, 21, sig, pos, 20);
return sig;
}
/** Converts from a JCE (ASN.1) formatted DSA signature to a RFC
* 2536 compliant signature.
*
* <p>rfc2536 format = T . R . S</p>
*
* where T is a number between 0 and 8, which is based on the DSA
* key length, and R & S are formatted to be exactly 20 bytes each
* (no leading null bytes).
*
* @param params the DSA parameters associated with the DSA key
* used to generate the signature.
* @param signature the ASN.1 formatted DSA signature.
* @return a RFC 2536 formatted DSA signature.
* @throws SignatureException if something is wrong with the ASN.1
* format.
*/
public static byte[] convertDSASignature(DSAParams params, byte[] signature)
throws SignatureException
{
if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT)
{
throw new SignatureException
("Invalid ASN.1 signature format: expected SEQ, INT");
}
byte r_pad = (byte) (signature[3] - 20);
if (signature[24 + r_pad] != ASN1_INT) {
throw new SignatureException
("Invalid ASN.1 signature format: expected SEQ, INT, INT");
}
log.trace("(start) ASN.1 DSA Sig:\n" + base64.toString(signature));
byte s_pad = (byte) (signature[25 + r_pad] - 20);
byte[] sig = new byte[41]; // all rfc2536 signatures are 41 bytes.
// Calculate T:
sig[0] = (byte) ((params.getP().bitLength() - 512) / 64);
// copy R value
if (r_pad >= 0)
{
System.arraycopy(signature, 4 + r_pad, sig, 1, 20);
}
else
{
// R is shorter than 20 bytes, so right justify the number
// (r_pad is negative here, remember?).
Arrays.fill(sig, 1 , 1 - r_pad, (byte) 0);
System.arraycopy(signature, 4, sig, 1 - r_pad, 20 + r_pad);
}
// copy S value
if (s_pad >= 0)
{
System.arraycopy(signature, 26 + r_pad + s_pad, sig, 21, 20);
}
else
{
// S is shorter than 20 bytes, so right justify the number
// (s_pad is negative here).
Arrays.fill(sig, 21, 21 - s_pad, (byte) 0);
System.arraycopy(signature, 26 + r_pad, sig, 21 - s_pad, 20 + s_pad);
}
if (r_pad < 0 || s_pad < 0)
{
log.trace("(finish ***) RFC 2536 DSA Sig:\n" + base64.toString(sig));
}
else
{
log.trace("(finish) RFC 2536 DSA Sig:\n" + base64.toString(sig));
}
return sig;
}
/** This is a convenience routine to help us classify records/RRsets.
*
* It charaterizes a record/RRset as one of the following classes:<br/>
* <dl>
* <dt>NORMAL</dt><dd>This record/set is properly within the zone
* an subject to all NXT and SIG processing.</dd>
* <dt>DELEGATION</dt><dd>This is a zone delegation point (or
* cut). It is used in NXT processing but is not signed.</dd>
* <dt>GLUE</dt><dd>This is a glue record and therefore not
* properly within the zone. It is not included in NXT or SIG
* processing. Normally glue records are A records, but this
* routine calls anything that is below a zone delegation
* glue.</dd>
* <dt>INVALID</dt><dd>This record doesn't even belong in the
* zone.</dd>
* </dl><br/>
* This method must be called successively on records in the
* canonical name ordering, and the caller must maintain the
* last_cut parameter.
* @param zonename the name of the zone that is being processed.
* @param name the name of the record/set under consideration.
* @param type the type of the record/set under consideration.
* @param last_cut the name of the last DELEGATION record/set that
* was encountered while iterating over the zone in canonical
* order.
*/
public static int recordSecType(Name zonename, Name name, int type,
Name last_cut)
{
// records not even in the zone itself are invalid.
if (!name.subdomain(zonename)) return RR_INVALID;
// records that are at the zonename node are definitely normal.
if (name.equals(zonename)) return RR_NORMAL;
// since we are not at zone level, any NS records are delegations
if (type == Type.NS) return RR_DELEGATION;
if (last_cut != null)
{
// if we are at the same level as a delegation point, but not an
// NS record, then we either a DS record or glue.
if (name.equals(last_cut))
{
if (type == Type.DS || type == Type.NXT ||
type == Type.NSEC) return RR_NORMAL;
// actually, this is probably INVALID, but it could be glue.
return RR_GLUE;
}
// below the delegation, we are glue
if (name.subdomain(last_cut)) return RR_GLUE;
}
return RR_NORMAL;
}
/** Given a canonical ordered list of records from a single zone,
* order the raw records into a list of RRsets.
*
* @param records a list of {@link org.xbill.DNS.Record} objects,
* in DNSSEC canonical order.
* @return a List of {@link org.xbill.DNS.RRset} objects.
*/
public static List assembleIntoRRsets(List records)
{
RRset rrset = new RRset();
ArrayList rrsets = new ArrayList();
for (Iterator i = records.iterator(); i.hasNext(); )
{
Object o = i.next();
if (! (o instanceof Record))
{
log.warn("assembleIntoRRsets: a non-record object was " +
"encountered and skipped: " + o + " (" + o.getClass() + ")");
continue;
}
Record r = (Record) o;
Name r_name = r.getName();
// First record
if (rrset.getName() == null)
{
rrset.addRR(r);
continue;
}
// Current record is part of the current RRset.
if (rrset.getName().equals(r.getName()) &&
rrset.getDClass() == r.getDClass() &&
((r.getType() == Type.RRSIG &&
rrset.getType() == ((RRSIGRecord)r).getTypeCovered()) ||
rrset.getType() == r.getType()))
{
rrset.addRR(r);
continue;
}
// otherwise, we have completed the RRset
rrsets.add(rrset);
// set up for the next set.
rrset = new RRset();
rrset.addRR(r);
}
// add the last rrset.
rrsets.add(rrset);
return rrsets;
}
/** A little private class to hold information about a given
* node. */
private static class NodeInfo
{
public Name name;
public int type;
public long ttl;
public int dclass;
public Set typemap;
public boolean isSecureNode; // opt-in support.
public boolean hasOptInSpan; // opt-in support.
public int nsecIndex;
public NodeInfo(Record r)
{
this.name = r.getName();
this.type = r.getType();
this.ttl = r.getTTL();
this.dclass = r.getDClass();
this.typemap = new HashSet();
this.isSecureNode = false;
this.hasOptInSpan = false;
addType(type);
}
public void addType(int type)
{
this.typemap.add(new Integer(type));
// Opt-In support.
if (type != Type.NS && type != Type.NSEC && type != Type.RRSIG)
{
isSecureNode = true;
}
}
public String toString()
{
StringBuffer sb = new StringBuffer(name.toString());
if (isSecureNode) sb.append("(S)");
if (hasOptInSpan) sb.append("(O)");
return sb.toString();
}
public int[] getTypes()
{
Object[] a = typemap.toArray();
int[] res = new int[a.length];
for (int i = 0; i < a.length; i++)
{
res[i] = ((Integer) a[i]).intValue();
}
return res;
}
}
/** Given a canonical (by name) ordered list of records in a zone,
* generate the NXT records in place.
*
* Note that the list that the records are stored in must support
* the listIterator.add() operation.
*
* @param zonename the name of the zone (used to distinguish
* between zone apex NS RRsets and delegations).
* @param records a list of {@link org.xbill.DNS.Record} objects in
* DNSSEC canonical order.
*/
public static void generateNSECRecords(Name zonename, List records)
{
// This works by iterating over a known sorted list of records.
NodeInfo last_node = null;
NodeInfo current_node = null;
Name last_cut = null;
int backup;
for (ListIterator i = records.listIterator(); i.hasNext(); )
{
Record r = (Record) i.next();
Name r_name = r.getName();
int r_type = r.getType();
int r_sectype = recordSecType(zonename, r_name, r_type, last_cut);
// skip irrelevant records
if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue;
// note our last delegation point so we can recognize glue.
if (r_sectype == RR_DELEGATION) last_cut = r_name;
// first node -- initialize
if (current_node == null)
{
current_node = new NodeInfo(r);
current_node.addType(Type.RRSIG);
current_node.addType(Type.NSEC);
continue;
}
// record name hasn't changed, so we are still on the same node.
if (r_name.equals(current_node.name))
{
current_node.addType(r_type);
continue;
}
if (last_node != null)
{
NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass,
last_node.ttl, current_node.name,
last_node.getTypes());
// Note: we have to add this through the iterator, otherwise
// the next access via the iterator will generate a
// ConcurrencyModificationException.
backup = i.nextIndex() - last_node.nsecIndex;
for (int j = 0; j < backup; j++) i.previous();
i.add(nsec);
for (int j = 0; j < backup; j++) i.next();
log.trace("Generated: " + nsec);
}
last_node = current_node;
current_node.nsecIndex = i.previousIndex();
current_node = new NodeInfo(r);
current_node.addType(Type.RRSIG);
current_node.addType(Type.NSEC);
}
// Generate next to last NSEC
if (last_node != null)
{
NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass,
last_node.ttl, current_node.name,
last_node.getTypes());
records.add(last_node.nsecIndex - 1, nsec);
log.trace("Generated: " + nsec);
}
// Generate last NSEC
NSECRecord nsec = new NSECRecord(current_node.name, current_node.dclass,
current_node.ttl, zonename,
current_node.getTypes());
records.add(nsec);
log.trace("Generated: " + nsec);
}
/** Given a canonical (by name) ordered list of records in a zone,
* generate the NXT records in place.
*
* Note thatthe list that the records are stored in must support
* the <code>listIterator.add</code> operation.
*
* @param zonename the name of the zone apex, used to distinguish
* between authoritative and delegation NS RRsets.
* @param records a list of {@link org.xbill.DNS.Record}s in DNSSEC
* canonical order.
* @param includeNames a list of names that should be in the NXT
* chain regardless. This may be null.
* @param beConservative if true, then Opt-In NXTs will only be
* generated where there is actually a span of insecure
* delegations.
*/
public static void generateOptInNSECRecords(Name zonename,
List records,
List includeNames,
boolean beConservative)
{
// This works by iterating over a known sorted list of records.
NodeInfo last_node = null;
NodeInfo current_node = null;
Name last_cut = null;
int backup;
HashSet includeSet = null;
if (includeNames != null)
{
includeSet = new HashSet(includeNames);
}
for (ListIterator i = records.listIterator(); i.hasNext(); )
{
Record r = (Record) i.next();
Name r_name = r.getName();
int r_type = r.getType();
int r_sectype = recordSecType(zonename, r_name, r_type, last_cut);
// skip irrelevant records
if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue;
// note our last delegation point so we can recognize glue.
if (r_sectype == RR_DELEGATION) last_cut = r_name;
// first node -- initialize
if (current_node == null)
{
current_node = new NodeInfo(r);
current_node.addType(Type.RRSIG);
continue;
}
// record name hasn't changed, so we are still on the same node.
if (r_name.equals(current_node.name))
{
current_node.addType(r_type);
continue;
}
// If the name is in the set of included names, mark it as
// secure.
if (includeSet != null && includeSet.contains(current_node.name))
{
current_node.isSecureNode = true;
}
if (last_node != null && current_node.isSecureNode)
{
// generate a NSEC record.
if (beConservative && !last_node.hasOptInSpan)
{
last_node.addType(Type.NSEC);
}
NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass,
last_node.ttl, current_node.name,
last_node.getTypes());
// Note: we have to add this through the iterator, otherwise
// the next access via the iterator will generate a
// ConcurrencyModificationException.
backup = i.nextIndex() - last_node.nsecIndex;
for (int j = 0; j < backup; j++) i.previous();
i.add(nsec);
for (int j = 0; j < backup; j++) i.next();
log.trace("Generated: " + nsec);
}
if (current_node.isSecureNode)
{
last_node = current_node;
}
else if (last_node != null)
{
// last_node does not change -- last_node is essentially the
// last *secure* node, and current_node is not secure.
// However, we need to note the passing of the insecure node.
last_node.hasOptInSpan = true;
}
current_node.nsecIndex = i.previousIndex();
current_node = new NodeInfo(r);
current_node.addType(Type.RRSIG);
}
// Generate next to last NSEC
if (last_node != null && current_node.isSecureNode)
{
// generate a NSEC record.
if (beConservative && !last_node.hasOptInSpan)
{
last_node.addType(Type.NSEC);
}
NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass,
last_node.ttl, current_node.name,
last_node.getTypes());
records.add(last_node.nsecIndex - 1, nsec);
log.trace("Generated: " + nsec);
}
// Generate last NSEC
NSECRecord nsec;
if (current_node.isSecureNode)
{
if (beConservative)
{
current_node.addType(Type.NSEC);
}
nsec = new NSECRecord(current_node.name, current_node.dclass,
current_node.ttl, zonename,
current_node.getTypes());
// we can just tack this on the end as we are working on the
// last node.
records.add(nsec);
}
else
{
nsec = new NSECRecord(last_node.name, last_node.dclass, last_node.ttl,
zonename, last_node.getTypes());
// We need to tack this on after the last secure node, not the
// end of the whole list.
records.add(last_node.nsecIndex, nsec);
}
log.trace("Generated: " + nsec);
}
/** Given a zone with DNSKEY records at delegation points, convert
* those KEY records into their corresponding DS records in place.
*
* @param zonename the name of the zone, used to reliably
* distinguish the zone apex from other records.
* @param records a list of {@link org.xbill.DNS.Record} objects.
*/
public static void generateDSRecords(Name zonename, List records)
throws IOException
{
for (ListIterator i = records.listIterator(); i.hasNext(); )
{
Record r = (Record) i.next();
if (r == null) continue; // this should never be true.
Name r_name = r.getName();
if (r_name == null) continue; // this should never be true.
// Convert non-zone level KEY records into DS records.
if (r.getType() == Type.DNSKEY && !r_name.equals(zonename))
{
DSRecord ds = calculateDSRecord((DNSKEYRecord) r, r.getTTL());
i.set(ds);
}
}
}
/** Given a zone, remove all records that are generated.
*
* @param zonename the name of the zone.
* @param records a list of {@link org.xbill.DNS.Record} objects.
*/
public static void removeGeneratedRecords(Name zonename, List records)
{
for (Iterator i = records.iterator(); i.hasNext(); )
{
Record r = (Record) i.next();
if (r.getType() == Type.RRSIG ||
r.getType() == Type.NSEC)
{
i.remove();
}
}
}
/** Remove duplicate records from a list of records. This routine
* presumes the list of records is in a canonical sorted order, at
* least on name and RR type.
*
* @param records a list of {@link org.xbill.DNS.Record} object, in
* sorted order.
*/
public static void removeDuplicateRecords(List records)
{
Record lastrec = null;
for (Iterator i = records.iterator(); i.hasNext(); )
{
Record r = (Record) i.next();
if (lastrec == null)
{
lastrec = r;
continue;
}
if (lastrec.equals(r))
{
i.remove();
continue;
}
lastrec = r;
}
}
/** Given a DNSKEY record, generate the DS record from it.
*
* @param keyrec the KEY record in question.
* @param ttl the desired TTL for the generated DS record. If
* zero, or negative, the original KEY RR's TTL will be used.
* @return the corresponding {@link org.xbill.DNS.DSRecord}
*/
public static DSRecord calculateDSRecord(DNSKEYRecord keyrec, long ttl)
throws IOException
{
if (keyrec == null) return null;
if (ttl <= 0) ttl = keyrec.getTTL();
DNSOutput os = new DNSOutput();
os.writeByteArray(keyrec.getName().toWireCanonical());
os.writeByteArray(keyrec.rdataToWireCanonical());
try
{
MessageDigest md = MessageDigest.getInstance("SHA");
byte[] digest = md.digest(os.toByteArray());
return new DSRecord(keyrec.getName(), keyrec.getDClass(), ttl,
keyrec.getFootprint(), keyrec.getAlgorithm(),
DSRecord.SHA1_DIGEST_ID, digest);
}
catch (NoSuchAlgorithmException e)
{
log.error("", e);
return null;
}
}
}

View File

@ -0,0 +1,182 @@
// $Id: TypeMap.java,v 1.5 2004/03/23 17:53:57 davidb Exp $
//
// Copyright (C) 2004 Verisign, Inc.
package com.verisignlabs.dnssec.security;
import java.util.*;
import org.xbill.DNS.Type;
import org.xbill.DNS.DNSOutput;
/** This class represents the multiple type maps of the NSEC
* record. Currently it is just used to convert the wire format type
* map to the int array that org.xbill.DNS.NSECRecord uses. */
public class TypeMap
{
private static final Integer[] integerArray = new Integer[0];
private Set typeSet;
public TypeMap()
{
this.typeSet = new HashSet();
}
/** Add the given type to the typemap. */
public void set(int type)
{
typeSet.add(new Integer(type));
}
/** Remove the given type from the type map. */
public void clear(int type)
{
typeSet.remove(new Integer(type));
}
/** @return true if the given type is present in the type map. */
public boolean get(int type)
{
return typeSet.contains(new Integer(type));
}
public static TypeMap fromTypes(int[] types)
{
TypeMap m = new TypeMap();
for (int i = 0; i < types.length; i++)
{
m.set(types[i]);
}
return m;
}
/** Given an array of bytes representing a wire-format type map,
* construct the TypeMap object. */
public static TypeMap fromBytes(byte[] map)
{
int m = 0;
TypeMap typemap = new TypeMap();
int map_number;
int byte_length;
while (m < map.length)
{
map_number = map[m++];
byte_length = map[m++];
for (int i = 0; i < byte_length; i++)
{
for (int j = 0; j < 8; j++)
{
if ( (map[m + i] & (1 << (7 - j))) != 0 )
{
typemap.set(map_number * 8 + j);
}
}
}
m += byte_length;
}
return typemap;
}
/** @return the normal string representation of the typemap. */
public String toString()
{
int[] types = getTypes();
Arrays.sort(types);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < types.length; i++)
{
sb.append(" ");
sb.append(Type.string(types[i]));
}
return sb.toString();
}
protected static void mapToWire(DNSOutput out, int[] types,
int base, int start, int end)
{
// calculate the length of this map by looking at the largest
// typecode in this section.
int max_type = types[end - 1] & 0xFF;
int map_length = (max_type / 8) + 1;
// write the map "header" -- the base and the length of the map.
out.writeU8(base & 0xFF);
out.writeU8(map_length & 0xFF);
// allocate a temporary scratch space for caculating the actual
// bitmap.
byte[] map = new byte[map_length];
// for each type in our sub-array, set its corresponding bit in the map.
for (int i = start; i < end; i++)
{
map[ (types[i] & 0xFF) / 8 ] |= ( 1 << (7 - types[i] % 8) );
}
// write out the resulting binary bitmap.
for (int i = 0; i < map.length; i++)
{
out.writeU8(map[i]);
}
}
public byte[] toWire()
{
int[] types = getTypes();
Arrays.sort(types);
int mapbase = -1;
int mapstart = -1;
DNSOutput out = new DNSOutput();
for (int i = 0; i < types.length; i++)
{
int base = types[i] >> 8;
if (base == mapbase) continue;
if (mapstart >= 0)
{
mapToWire(out, types, mapbase, mapstart, i);
}
mapbase = base;
mapstart = i;
}
mapToWire(out, types, mapbase, mapstart, types.length);
return out.toByteArray();
}
public int[] getTypes()
{
Integer[] a = (Integer[]) typeSet.toArray(integerArray);
int[] res = new int[a.length];
for (int i = 0; i < res.length; i++) {
res[i] = a[i].intValue();
}
return res;
}
public static int[] fromWireToTypes(byte[] wire_fmt)
{
return TypeMap.fromBytes(wire_fmt).getTypes();
}
public static byte[] fromTypesToWire(int[] types)
{
return TypeMap.fromTypes(types).toWire();
}
}

View File

@ -0,0 +1,138 @@
// $Id: ZoneUtils.java,v 1.3 2004/01/15 17:32:18 davidb Exp $
//
// Copyright (C) 2003 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.security;
import java.util.*;
import java.io.*;
import org.xbill.DNS.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** This class contains a bunch of utility methods that are generally
* useful in manipulating zones.
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 1.3 $
*/
public class ZoneUtils
{
private static Log log;
static {
log = LogFactory.getLog(ZoneUtils.class);
}
/** Load a zone file.
*
* @param zonefile the filename/path of the zonefile to read.
* @param origin the origin to use for the zonefile (may be null if
* the origin is specified in the zone file itself).
* @return a {@link java.util.List} of {@link org.xbill.DNS.Record}
* objects.
* @throws IOException if something goes wrong reading the zone
* file.
*/
public static List readZoneFile(String zonefile, Name origin)
throws IOException
{
ArrayList records = new ArrayList();
Master m = new Master(zonefile, origin);
Record r = null;
while ( (r = m.nextRecord()) != null )
{
records.add(r);
}
return records;
}
/** Write the records out into a zone file.
*
* @param records a {@link java.util.List} of {@link
* org.xbill.DNS.Record} objects forming a zone.
* @param zonefile the file to write to. If null or equal to "-",
* System.out is used.
*/
public static void writeZoneFile(List records, String zonefile)
throws IOException
{
PrintWriter out = null;
if (zonefile == null || zonefile.equals("-"))
{
out = new PrintWriter(System.out);
}
else
{
out = new PrintWriter(new BufferedWriter(new FileWriter(zonefile)));
}
for (Iterator i = records.iterator(); i.hasNext(); )
{
out.println(i.next());
}
out.close();
}
/** Given just the list of records, determine the zone name
* (origin).
*
* @param records a list of {@link org.xbill.DNS.Record} or {@link
* org.xbill.DNS.RRset} objects.
* @return the zone name, if found. null if one couldn't be found.q
*/
public static Name findZoneName(List records)
{
for (Iterator i = records.iterator(); i.hasNext(); )
{
int type = 0;
Name n = null;
Object o = i.next();
if (o instanceof Record)
{
Record r = (Record) o;
type = r.getType();
n = r.getName();
}
else if (o instanceof RRset)
{
RRset r = (RRset) o;
type = r.getType();
n = r.getName();
}
if (type == Type.SOA) return n;
}
return null;
}
}

View File

@ -0,0 +1,35 @@
<BODY BGCOLOR="#FFFFFF">
This package contains a number of utility classes that can be used to
implement DNSSEC tool (key generation, zone signing, etc.)
functionality.
<p>
<center>
<table width="90%" border=1 cellpadding=10 cellspacing=0>
<tr><td class="TableRowColor">
Copyright &copy; 2003 Verisign, Inc. by
<a href="mailto:davidb@verisignlabs.com">David Blacka</a><P>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.<P>
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.<P>
You should have received a copy of the
<a href="http://www.gnu.org/copyleft/lgpl.html">GNU Library General Public License</a>
along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
</td></tr>
</table><P>
</center>
</BODY>

4
svn-commit.tmp Normal file
View File

@ -0,0 +1,4 @@
signing tools project
--This line, and those below, will be ignored--
A https://svn.verisignlabs.com/main/dnssec/sectools/trunk