eclipse reformatting.
git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@242 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
		
							parent
							
								
									faae654a23
								
							
						
					
					
						commit
						453bf283ba
					
				@ -59,447 +59,504 @@ import com.verisignlabs.dnssec.security.*;
 | 
				
			|||||||
 * @author $Author: davidb $
 | 
					 * @author $Author: davidb $
 | 
				
			||||||
 * @version $Revision: 2235 $
 | 
					 * @version $Revision: 2235 $
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class SignKeyset {
 | 
					public class SignKeyset
 | 
				
			||||||
    private static Logger log;
 | 
					{
 | 
				
			||||||
 | 
					  private static Logger log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					  /**
 | 
				
			||||||
     * This is an inner class used to hold all of the command line option state.
 | 
					   * This is an inner class used to hold all of the command line option state.
 | 
				
			||||||
     */
 | 
					   */
 | 
				
			||||||
    private static class CLIState {
 | 
					  private static class CLIState
 | 
				
			||||||
        private Options opts;
 | 
					  {
 | 
				
			||||||
        private File    keyDirectory = null;
 | 
					    private Options opts;
 | 
				
			||||||
        public String[] keyFiles     = null;
 | 
					    private File    keyDirectory = null;
 | 
				
			||||||
        public Date     start        = null;
 | 
					    public String[] keyFiles     = null;
 | 
				
			||||||
        public Date     expire       = null;
 | 
					    public Date     start        = null;
 | 
				
			||||||
        public String   inputfile    = null;
 | 
					    public Date     expire       = null;
 | 
				
			||||||
        public String   outputfile   = null;
 | 
					    public String   inputfile    = null;
 | 
				
			||||||
        public boolean  verifySigs   = false;
 | 
					    public String   outputfile   = null;
 | 
				
			||||||
 | 
					    public boolean  verifySigs   = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public CLIState() {
 | 
					    public CLIState()
 | 
				
			||||||
            setupCLI();
 | 
					    {
 | 
				
			||||||
        }
 | 
					      setupCLI();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * Set up the command line options.
 | 
					 | 
				
			||||||
         * 
 | 
					 | 
				
			||||||
         * @return a set of command line options.
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        private void setupCLI() {
 | 
					 | 
				
			||||||
            opts = new Options();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // boolean options
 | 
					 | 
				
			||||||
            opts.addOption("h", "help", false, "Print this message.");
 | 
					 | 
				
			||||||
            opts.addOption("a", "verify", false, "verify generated signatures>");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasOptionalArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withLongOpt("verbose");
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("level");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("verbosity level.");
 | 
					 | 
				
			||||||
            // Argument options
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('v'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("dir");
 | 
					 | 
				
			||||||
            OptionBuilder.withLongOpt("key-directory");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("directory to find key files (default '.').");
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('D'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("time/offset");
 | 
					 | 
				
			||||||
            OptionBuilder.withLongOpt("start-time");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('s'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("time/offset");
 | 
					 | 
				
			||||||
            OptionBuilder.withLongOpt("expire-time");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("signature expiration time (default is start-time + 30 days).");
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('e'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("outfile");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("file the signed keyset is written to.");
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('f'));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void parseCommandLine(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();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Logger rootLogger = Logger.getLogger("");
 | 
					 | 
				
			||||||
            if (cli.hasOption('v'))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              int value = parseInt(cli.getOptionValue('v'), -1);
 | 
					 | 
				
			||||||
              switch (value)
 | 
					 | 
				
			||||||
              {
 | 
					 | 
				
			||||||
                case 0:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.OFF);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 1:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.SEVERE);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 2:
 | 
					 | 
				
			||||||
                default:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.WARNING);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 3:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.INFO);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 4:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.CONFIG);
 | 
					 | 
				
			||||||
                case 5:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.FINE);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 6:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.ALL);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            // I hate java.util.logging, btw.
 | 
					 | 
				
			||||||
            for (Handler h : rootLogger.getHandlers())
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              h.setLevel(rootLogger.getLevel());
 | 
					 | 
				
			||||||
              h.setFormatter(new BareLogFormatter());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (cli.hasOption('a')) verifySigs = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ((optstr = cli.getOptionValue('D')) != null) {
 | 
					 | 
				
			||||||
                keyDirectory = new File(optstr);
 | 
					 | 
				
			||||||
                if (!keyDirectory.isDirectory()) {
 | 
					 | 
				
			||||||
                    System.err.println("error: " + optstr
 | 
					 | 
				
			||||||
                            + " is not a directory");
 | 
					 | 
				
			||||||
                    usage();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            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');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            String[] files = cli.getArgs();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (files.length < 1) {
 | 
					 | 
				
			||||||
                System.err.println("error: missing zone file and/or key files");
 | 
					 | 
				
			||||||
                usage();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            inputfile = files[0];
 | 
					 | 
				
			||||||
            if (files.length > 1) {
 | 
					 | 
				
			||||||
                keyFiles = new String[files.length - 1];
 | 
					 | 
				
			||||||
                System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /** Print out the usage and help statements, then quit. */
 | 
					 | 
				
			||||||
        private void usage() {
 | 
					 | 
				
			||||||
            HelpFormatter f = new HelpFormatter();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            PrintWriter out = new PrintWriter(System.err);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // print our own usage statement:
 | 
					 | 
				
			||||||
            f.printHelp(out, 75, "jdnssec-signkeyset [..options..] "
 | 
					 | 
				
			||||||
                    + "dnskeyset_file [key_file ...]", null, opts,
 | 
					 | 
				
			||||||
                        HelpFormatter.DEFAULT_LEFT_PAD,
 | 
					 | 
				
			||||||
                        HelpFormatter.DEFAULT_DESC_PAD,
 | 
					 | 
				
			||||||
                        "\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            out.flush();
 | 
					 | 
				
			||||||
            System.exit(64);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * This is just a convenience method for parsing integers from strings.
 | 
					     * Set up the command line options.
 | 
				
			||||||
     * 
 | 
					     *
 | 
				
			||||||
     * @param s
 | 
					     * @return a set of command line options.
 | 
				
			||||||
     *            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) {
 | 
					    private void setupCLI()
 | 
				
			||||||
        try {
 | 
					    {
 | 
				
			||||||
            int v = Integer.parseInt(s);
 | 
					      opts = new Options();
 | 
				
			||||||
            return v;
 | 
					
 | 
				
			||||||
        } catch (NumberFormatException e) {
 | 
					      // boolean options
 | 
				
			||||||
            return def;
 | 
					      opts.addOption("h", "help", false, "Print this message.");
 | 
				
			||||||
        }
 | 
					      opts.addOption("a", "verify", false, "verify generated signatures>");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasOptionalArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withLongOpt("verbose");
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("level");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("verbosity level.");
 | 
				
			||||||
 | 
					      // Argument options
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('v'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("dir");
 | 
				
			||||||
 | 
					      OptionBuilder.withLongOpt("key-directory");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("directory to find key files (default '.').");
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('D'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("time/offset");
 | 
				
			||||||
 | 
					      OptionBuilder.withLongOpt("start-time");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('s'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("time/offset");
 | 
				
			||||||
 | 
					      OptionBuilder.withLongOpt("expire-time");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("signature expiration time (default is start-time + 30 days).");
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('e'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("outfile");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("file the signed keyset is written to.");
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('f'));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    public void parseCommandLine(String[] args)
 | 
				
			||||||
     * Verify the generated signatures.
 | 
					        throws org.apache.commons.cli.ParseException, ParseException, IOException
 | 
				
			||||||
     * 
 | 
					    {
 | 
				
			||||||
     * @param zonename
 | 
					      CommandLineParser cli_parser = new PosixParser();
 | 
				
			||||||
     *            the origin name of the zone.
 | 
					      CommandLine cli = cli_parser.parse(opts, args);
 | 
				
			||||||
     * @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 verifySigs(Name zonename, List records, List keypairs) {
 | 
					 | 
				
			||||||
        boolean secure = true;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DnsSecVerifier verifier = new DnsSecVerifier();
 | 
					      String optstr = null;
 | 
				
			||||||
 | 
					      if (cli.hasOption('h')) usage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (Iterator i = keypairs.iterator(); i.hasNext();) {
 | 
					      Logger rootLogger = Logger.getLogger("");
 | 
				
			||||||
            verifier.addTrustedKey((DnsKeyPair) i.next());
 | 
					      if (cli.hasOption('v'))
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        int value = parseInt(cli.getOptionValue('v'), -1);
 | 
				
			||||||
 | 
					        switch (value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          case 0:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.OFF);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 1:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.SEVERE);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 2:
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.WARNING);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 3:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.INFO);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 4:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.CONFIG);
 | 
				
			||||||
 | 
					          case 5:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.FINE);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 6:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.ALL);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // I hate java.util.logging, btw.
 | 
				
			||||||
 | 
					      for (Handler h : rootLogger.getHandlers())
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        h.setLevel(rootLogger.getLevel());
 | 
				
			||||||
 | 
					        h.setFormatter(new BareLogFormatter());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        verifier.setVerifyAllSigs(true);
 | 
					      if (cli.hasOption('a')) verifySigs = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        List rrsets = SignUtils.assembleIntoRRsets(records);
 | 
					      if ((optstr = cli.getOptionValue('D')) != null)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
        for (Iterator i = rrsets.iterator(); i.hasNext();) {
 | 
					        keyDirectory = new File(optstr);
 | 
				
			||||||
            RRset rrset = (RRset) i.next();
 | 
					        if (!keyDirectory.isDirectory())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            // skip unsigned rrsets.
 | 
					          System.err.println("error: " + optstr + " is not a directory");
 | 
				
			||||||
            if (!rrset.sigs().hasNext()) continue;
 | 
					          usage();
 | 
				
			||||||
 | 
					 | 
				
			||||||
            int result = verifier.verify(rrset, null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (result != DNSSEC.Secure) {
 | 
					 | 
				
			||||||
                log.fine("Signatures did not verify for RRset: (" + result
 | 
					 | 
				
			||||||
                        + "): " + rrset);
 | 
					 | 
				
			||||||
                secure = false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return secure;
 | 
					      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');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      String[] files = cli.getArgs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (files.length < 1)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        System.err.println("error: missing zone file and/or key files");
 | 
				
			||||||
 | 
					        usage();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      inputfile = files[0];
 | 
				
			||||||
 | 
					      if (files.length > 1)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        keyFiles = new String[files.length - 1];
 | 
				
			||||||
 | 
					        System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /** Print out the usage and help statements, then quit. */
 | 
				
			||||||
     * Load the key pairs from the key files.
 | 
					    private void usage()
 | 
				
			||||||
     * 
 | 
					    {
 | 
				
			||||||
     * @param keyfiles
 | 
					      HelpFormatter f = new HelpFormatter();
 | 
				
			||||||
     *            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;
 | 
					      PrintWriter out = new PrintWriter(System.err);
 | 
				
			||||||
        if (len <= 0) return null;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ArrayList keys = new ArrayList(len);
 | 
					      // print our own usage statement:
 | 
				
			||||||
 | 
					      f.printHelp(out, 75, "jdnssec-signkeyset [..options..] "
 | 
				
			||||||
 | 
					                      + "dnskeyset_file [key_file ...]", null, opts,
 | 
				
			||||||
 | 
					                  HelpFormatter.DEFAULT_LEFT_PAD,
 | 
				
			||||||
 | 
					                  HelpFormatter.DEFAULT_DESC_PAD,
 | 
				
			||||||
 | 
					                  "\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (int i = start_index; i < keyfiles.length; i++) {
 | 
					      out.flush();
 | 
				
			||||||
            DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
 | 
					      System.exit(64);
 | 
				
			||||||
            if (k != null) keys.add(k);
 | 
					    }
 | 
				
			||||||
        }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return keys;
 | 
					  /**
 | 
				
			||||||
 | 
					   * 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 verifySigs(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());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static class KeyFileFilter implements FileFilter {
 | 
					    verifier.setVerifyAllSigs(true);
 | 
				
			||||||
        private String prefix;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public KeyFileFilter(Name origin) {
 | 
					    List rrsets = SignUtils.assembleIntoRRsets(records);
 | 
				
			||||||
            prefix = "K" + origin.toString();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public boolean accept(File pathname) {
 | 
					    for (Iterator i = rrsets.iterator(); i.hasNext();)
 | 
				
			||||||
            if (!pathname.isFile()) return false;
 | 
					    {
 | 
				
			||||||
            String name = pathname.getName();
 | 
					      RRset rrset = (RRset) i.next();
 | 
				
			||||||
            if (name.startsWith(prefix) && name.endsWith(".private"))
 | 
					
 | 
				
			||||||
                return true;
 | 
					      // skip unsigned rrsets.
 | 
				
			||||||
            return false;
 | 
					      if (!rrset.sigs().hasNext()) continue;
 | 
				
			||||||
        }
 | 
					
 | 
				
			||||||
 | 
					      int result = verifier.verify(rrset, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (result != DNSSEC.Secure)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset);
 | 
				
			||||||
 | 
					        secure = false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static List findZoneKeys(File inDirectory, Name zonename)
 | 
					    return secure;
 | 
				
			||||||
            throws IOException {
 | 
					  }
 | 
				
			||||||
        if (inDirectory == null) {
 | 
					 | 
				
			||||||
            inDirectory = new File(".");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // get the list of "K<zone>.*.private files.
 | 
					  /**
 | 
				
			||||||
        FileFilter filter = new KeyFileFilter(zonename);
 | 
					   * Load the key pairs from the key files.
 | 
				
			||||||
        File[] files = inDirectory.listFiles(filter);
 | 
					   *
 | 
				
			||||||
 | 
					   * @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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // read in all of the records
 | 
					    int len = keyfiles.length - start_index;
 | 
				
			||||||
        ArrayList keys = new ArrayList();
 | 
					    if (len <= 0) return null;
 | 
				
			||||||
        for (int i = 0; i < files.length; i++) {
 | 
					 | 
				
			||||||
            DnsKeyPair p = BINDKeyUtils.loadKeyPair(files[i].getName(),
 | 
					 | 
				
			||||||
                                                    inDirectory);
 | 
					 | 
				
			||||||
            keys.add(p);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (keys.size() > 0) return keys;
 | 
					    ArrayList keys = new ArrayList(len);
 | 
				
			||||||
        return null;
 | 
					
 | 
				
			||||||
 | 
					    for (int i = start_index; i < keyfiles.length; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
 | 
				
			||||||
 | 
					      if (k != null) keys.add(k);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    return keys;
 | 
				
			||||||
     * 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);
 | 
					  private static class KeyFileFilter implements FileFilter
 | 
				
			||||||
        }
 | 
					  {
 | 
				
			||||||
 | 
					    private String prefix;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (duration.startsWith("+")) {
 | 
					    public KeyFileFilter(Name origin)
 | 
				
			||||||
            long offset = (long) parseInt(duration.substring(1), 0) * 1000;
 | 
					    {
 | 
				
			||||||
            return new Date(start.getTime() + offset);
 | 
					      prefix = "K" + origin.toString();
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
 | 
					 | 
				
			||||||
        dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
 | 
					 | 
				
			||||||
        return dateFormatter.parse(duration);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void execute(CLIState state) throws Exception {
 | 
					    public boolean accept(File pathname)
 | 
				
			||||||
        // Read in the zone
 | 
					    {
 | 
				
			||||||
        List records = ZoneUtils.readZoneFile(state.inputfile, null);
 | 
					      if (!pathname.isFile()) return false;
 | 
				
			||||||
        if (records == null || records.size() == 0) {
 | 
					      String name = pathname.getName();
 | 
				
			||||||
            System.err.println("error: empty keyset file");
 | 
					      if (name.startsWith(prefix) && name.endsWith(".private")) return true;
 | 
				
			||||||
            state.usage();
 | 
					      return false;
 | 
				
			||||||
        }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
        // Make sure that all records are DNSKEYs with the same name.
 | 
					 | 
				
			||||||
        Name keysetName = null;
 | 
					 | 
				
			||||||
        RRset keyset = new RRset();
 | 
					 | 
				
			||||||
        for (Iterator i = records.iterator(); i.hasNext();) {
 | 
					 | 
				
			||||||
            Record r = (Record) i.next();
 | 
					 | 
				
			||||||
            if (r.getType() != Type.DNSKEY) {
 | 
					 | 
				
			||||||
                System.err.println("error: Non DNSKEY RR found in keyset: " + r);
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (keysetName == null) {
 | 
					 | 
				
			||||||
                keysetName = r.getName();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (!r.getName().equals(keysetName)) {
 | 
					 | 
				
			||||||
                System.err.println("error: DNSKEY with a different name found!");
 | 
					 | 
				
			||||||
                state.usage();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            keyset.addRR(r);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (keyset.size() == 0) {
 | 
					 | 
				
			||||||
            System.err.println("error: No DNSKEYs found in keyset file");
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Load the key pairs.
 | 
					 | 
				
			||||||
        List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // If we *still* don't have any key pairs, look for keys the key
 | 
					 | 
				
			||||||
        // directory
 | 
					 | 
				
			||||||
        // that match
 | 
					 | 
				
			||||||
        if (keypairs == null) {
 | 
					 | 
				
			||||||
            keypairs = findZoneKeys(state.keyDirectory, keysetName);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // If there *still* aren't any ZSKs defined, bail.
 | 
					 | 
				
			||||||
        if (keypairs == null || keypairs.size() == 0) {
 | 
					 | 
				
			||||||
            System.err.println("error: No signing keys could be determined.");
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // default the output file, if not set.
 | 
					 | 
				
			||||||
        if (state.outputfile == null) {
 | 
					 | 
				
			||||||
            if (keysetName.isAbsolute()) {
 | 
					 | 
				
			||||||
                state.outputfile = keysetName + "signed_keyset";
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                state.outputfile = keysetName + ".signed_keyset";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        JCEDnsSecSigner signer = new JCEDnsSecSigner();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        List sigs = signer.signRRset(keyset, keypairs, state.start,
 | 
					 | 
				
			||||||
                                     state.expire);
 | 
					 | 
				
			||||||
        for (Iterator i = sigs.iterator(); i.hasNext();) {
 | 
					 | 
				
			||||||
            keyset.addRR((Record) i.next());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // write out the signed RRset
 | 
					 | 
				
			||||||
        List signed_records = new ArrayList();
 | 
					 | 
				
			||||||
        for (Iterator i = keyset.rrs(); i.hasNext();) {
 | 
					 | 
				
			||||||
            signed_records.add(i.next());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        for (Iterator i = keyset.sigs(); i.hasNext();) {
 | 
					 | 
				
			||||||
            signed_records.add(i.next());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 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) {
 | 
					 | 
				
			||||||
            log.fine("verifying generated signatures");
 | 
					 | 
				
			||||||
            boolean res = verifySigs(keysetName, 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.");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static List findZoneKeys(File inDirectory, Name zonename) throws IOException
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (inDirectory == null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      inDirectory = new File(".");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void main(String[] args) {
 | 
					    // get the list of "K<zone>.*.private files.
 | 
				
			||||||
        CLIState state = new CLIState();
 | 
					    FileFilter filter = new KeyFileFilter(zonename);
 | 
				
			||||||
        try {
 | 
					    File[] files = inDirectory.listFiles(filter);
 | 
				
			||||||
            state.parseCommandLine(args);
 | 
					 | 
				
			||||||
        } catch (UnrecognizedOptionException e) {
 | 
					 | 
				
			||||||
            System.err.println("error: unknown option encountered: "
 | 
					 | 
				
			||||||
                    + e.getMessage());
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        } catch (AlreadySelectedException e) {
 | 
					 | 
				
			||||||
            System.err.println("error: mutually exclusive options have "
 | 
					 | 
				
			||||||
                    + "been selected:\n     " + e.getMessage());
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        } catch (Exception e) {
 | 
					 | 
				
			||||||
            System.err.println("error: unknown command line parsing exception:");
 | 
					 | 
				
			||||||
            e.printStackTrace();
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        log = Logger.getLogger(SignKeyset.class.toString());
 | 
					    // read in all of the records
 | 
				
			||||||
 | 
					    ArrayList keys = new ArrayList();
 | 
				
			||||||
        try {
 | 
					    for (int i = 0; i < files.length; i++)
 | 
				
			||||||
            execute(state);
 | 
					    {
 | 
				
			||||||
        } catch (Exception e) {
 | 
					      DnsKeyPair p = BINDKeyUtils.loadKeyPair(files[i].getName(), inDirectory);
 | 
				
			||||||
            e.printStackTrace();
 | 
					      keys.add(p);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (keys.size() > 0) return keys;
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 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);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public static void execute(CLIState state) throws Exception
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    // Read in the zone
 | 
				
			||||||
 | 
					    List records = ZoneUtils.readZoneFile(state.inputfile, null);
 | 
				
			||||||
 | 
					    if (records == null || records.size() == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: empty keyset file");
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Make sure that all records are DNSKEYs with the same name.
 | 
				
			||||||
 | 
					    Name keysetName = null;
 | 
				
			||||||
 | 
					    RRset keyset = new RRset();
 | 
				
			||||||
 | 
					    for (Iterator i = records.iterator(); i.hasNext();)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      Record r = (Record) i.next();
 | 
				
			||||||
 | 
					      if (r.getType() != Type.DNSKEY)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        System.err.println("error: Non DNSKEY RR found in keyset: " + r);
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (keysetName == null)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        keysetName = r.getName();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!r.getName().equals(keysetName))
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        System.err.println("error: DNSKEY with a different name found!");
 | 
				
			||||||
 | 
					        state.usage();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      keyset.addRR(r);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (keyset.size() == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: No DNSKEYs found in keyset file");
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Load the key pairs.
 | 
				
			||||||
 | 
					    List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If we *still* don't have any key pairs, look for keys the key
 | 
				
			||||||
 | 
					    // directory
 | 
				
			||||||
 | 
					    // that match
 | 
				
			||||||
 | 
					    if (keypairs == null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      keypairs = findZoneKeys(state.keyDirectory, keysetName);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If there *still* aren't any ZSKs defined, bail.
 | 
				
			||||||
 | 
					    if (keypairs == null || keypairs.size() == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: No signing keys could be determined.");
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // default the output file, if not set.
 | 
				
			||||||
 | 
					    if (state.outputfile == null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      if (keysetName.isAbsolute())
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        state.outputfile = keysetName + "signed_keyset";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        state.outputfile = keysetName + ".signed_keyset";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JCEDnsSecSigner signer = new JCEDnsSecSigner();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    List sigs = signer.signRRset(keyset, keypairs, state.start, state.expire);
 | 
				
			||||||
 | 
					    for (Iterator i = sigs.iterator(); i.hasNext();)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      keyset.addRR((Record) i.next());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // write out the signed RRset
 | 
				
			||||||
 | 
					    List signed_records = new ArrayList();
 | 
				
			||||||
 | 
					    for (Iterator i = keyset.rrs(); i.hasNext();)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      signed_records.add(i.next());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (Iterator i = keyset.sigs(); i.hasNext();)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      signed_records.add(i.next());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      log.fine("verifying generated signatures");
 | 
				
			||||||
 | 
					      boolean res = verifySigs(keysetName, 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)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    CLIState state = new CLIState();
 | 
				
			||||||
 | 
					    try
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      state.parseCommandLine(args);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (UnrecognizedOptionException e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: unknown option encountered: " + e.getMessage());
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (AlreadySelectedException e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: mutually exclusive options have "
 | 
				
			||||||
 | 
					          + "been selected:\n     " + e.getMessage());
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (Exception e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: unknown command line parsing exception:");
 | 
				
			||||||
 | 
					      e.printStackTrace();
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log = Logger.getLogger(SignKeyset.class.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      execute(state);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (Exception e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      e.printStackTrace();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -60,423 +60,474 @@ import com.verisignlabs.dnssec.security.*;
 | 
				
			|||||||
 * @author $Author: davidb $
 | 
					 * @author $Author: davidb $
 | 
				
			||||||
 * @version $Revision: 2235 $
 | 
					 * @version $Revision: 2235 $
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class SignRRset {
 | 
					public class SignRRset
 | 
				
			||||||
    private static Logger log;
 | 
					{
 | 
				
			||||||
 | 
					  private static Logger log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					  /**
 | 
				
			||||||
     * This is an inner class used to hold all of the command line option state.
 | 
					   * This is an inner class used to hold all of the command line option state.
 | 
				
			||||||
     */
 | 
					   */
 | 
				
			||||||
    private static class CLIState {
 | 
					  private static class CLIState
 | 
				
			||||||
        private Options opts;
 | 
					  {
 | 
				
			||||||
        private File    keyDirectory = null;
 | 
					    private Options opts;
 | 
				
			||||||
        public String[] keyFiles     = null;
 | 
					    private File    keyDirectory = null;
 | 
				
			||||||
        public Date     start        = null;
 | 
					    public String[] keyFiles     = null;
 | 
				
			||||||
        public Date     expire       = null;
 | 
					    public Date     start        = null;
 | 
				
			||||||
        public String   inputfile    = null;
 | 
					    public Date     expire       = null;
 | 
				
			||||||
        public String   outputfile   = null;
 | 
					    public String   inputfile    = null;
 | 
				
			||||||
        public boolean  verifySigs   = false;
 | 
					    public String   outputfile   = null;
 | 
				
			||||||
 | 
					    public boolean  verifySigs   = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public CLIState() {
 | 
					    public CLIState()
 | 
				
			||||||
            setupCLI();
 | 
					    {
 | 
				
			||||||
        }
 | 
					      setupCLI();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * Set up the command line options.
 | 
					 | 
				
			||||||
         * 
 | 
					 | 
				
			||||||
         * @return a set of command line options.
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        private void setupCLI() {
 | 
					 | 
				
			||||||
            opts = new Options();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // boolean options
 | 
					 | 
				
			||||||
            opts.addOption("h", "help", false, "Print this message.");
 | 
					 | 
				
			||||||
            opts.addOption("a", "verify", false, "verify generated signatures>");
 | 
					 | 
				
			||||||
            opts.addOption("m", "multiline", false, "Use a multiline format");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasOptionalArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withLongOpt("verbose");
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("level");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("verbosity level.");
 | 
					 | 
				
			||||||
            // Argument options
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('v'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("dir");
 | 
					 | 
				
			||||||
            OptionBuilder.withLongOpt("key-directory");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("directory to find key files (default '.').");
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('D'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("time/offset");
 | 
					 | 
				
			||||||
            OptionBuilder.withLongOpt("start-time");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('s'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("time/offset");
 | 
					 | 
				
			||||||
            OptionBuilder.withLongOpt("expire-time");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("signature expiration time (default is start-time + 30 days).");
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('e'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            OptionBuilder.hasArg();
 | 
					 | 
				
			||||||
            OptionBuilder.withArgName("outfile");
 | 
					 | 
				
			||||||
            OptionBuilder.withDescription("file the signed rrset is written to.");
 | 
					 | 
				
			||||||
            opts.addOption(OptionBuilder.create('f'));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void parseCommandLine(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();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Logger rootLogger = Logger.getLogger("");
 | 
					 | 
				
			||||||
            if (cli.hasOption('v'))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              int value = parseInt(cli.getOptionValue('v'), -1);
 | 
					 | 
				
			||||||
              switch (value)
 | 
					 | 
				
			||||||
              {
 | 
					 | 
				
			||||||
                case 0:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.OFF);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 1:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.SEVERE);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 2:
 | 
					 | 
				
			||||||
                default:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.WARNING);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 3:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.INFO);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 4:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.CONFIG);
 | 
					 | 
				
			||||||
                case 5:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.FINE);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                case 6:
 | 
					 | 
				
			||||||
                  rootLogger.setLevel(Level.ALL);
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            // I hate java.util.logging, btw.
 | 
					 | 
				
			||||||
            for (Handler h : rootLogger.getHandlers())
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              h.setLevel(rootLogger.getLevel());
 | 
					 | 
				
			||||||
              h.setFormatter(new BareLogFormatter());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (cli.hasOption('a')) verifySigs = true;
 | 
					 | 
				
			||||||
            if (cli.hasOption('m')) org.xbill.DNS.Options.set("multiline");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ((optstr = cli.getOptionValue('D')) != null) {
 | 
					 | 
				
			||||||
                keyDirectory = new File(optstr);
 | 
					 | 
				
			||||||
                if (!keyDirectory.isDirectory()) {
 | 
					 | 
				
			||||||
                    System.err.println("error: " + optstr
 | 
					 | 
				
			||||||
                            + " is not a directory");
 | 
					 | 
				
			||||||
                    usage();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            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');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            String[] files = cli.getArgs();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (files.length < 1) {
 | 
					 | 
				
			||||||
                System.err.println("error: missing zone file and/or key files");
 | 
					 | 
				
			||||||
                usage();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            inputfile = files[0];
 | 
					 | 
				
			||||||
            if (files.length > 1) {
 | 
					 | 
				
			||||||
                keyFiles = new String[files.length - 1];
 | 
					 | 
				
			||||||
                System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /** Print out the usage and help statements, then quit. */
 | 
					 | 
				
			||||||
        private void usage() {
 | 
					 | 
				
			||||||
            HelpFormatter f = new HelpFormatter();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            PrintWriter out = new PrintWriter(System.err);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // print our own usage statement:
 | 
					 | 
				
			||||||
            f.printHelp(out, 75, "jdnssec-signrrset [..options..] "
 | 
					 | 
				
			||||||
                    + "rrset_file key_file [key_file ...]", null, opts,
 | 
					 | 
				
			||||||
                        HelpFormatter.DEFAULT_LEFT_PAD,
 | 
					 | 
				
			||||||
                        HelpFormatter.DEFAULT_DESC_PAD,
 | 
					 | 
				
			||||||
                        "\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            out.flush();
 | 
					 | 
				
			||||||
            System.exit(64);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * This is just a convenience method for parsing integers from strings.
 | 
					     * Set up the command line options.
 | 
				
			||||||
     * 
 | 
					     *
 | 
				
			||||||
     * @param s
 | 
					     * @return a set of command line options.
 | 
				
			||||||
     *            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) {
 | 
					    private void setupCLI()
 | 
				
			||||||
        try {
 | 
					    {
 | 
				
			||||||
            int v = Integer.parseInt(s);
 | 
					      opts = new Options();
 | 
				
			||||||
            return v;
 | 
					
 | 
				
			||||||
        } catch (NumberFormatException e) {
 | 
					      // boolean options
 | 
				
			||||||
            return def;
 | 
					      opts.addOption("h", "help", false, "Print this message.");
 | 
				
			||||||
        }
 | 
					      opts.addOption("a", "verify", false, "verify generated signatures>");
 | 
				
			||||||
 | 
					      opts.addOption("m", "multiline", false, "Use a multiline format");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasOptionalArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withLongOpt("verbose");
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("level");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("verbosity level.");
 | 
				
			||||||
 | 
					      // Argument options
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('v'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("dir");
 | 
				
			||||||
 | 
					      OptionBuilder.withLongOpt("key-directory");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("directory to find key files (default '.').");
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('D'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("time/offset");
 | 
				
			||||||
 | 
					      OptionBuilder.withLongOpt("start-time");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('s'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("time/offset");
 | 
				
			||||||
 | 
					      OptionBuilder.withLongOpt("expire-time");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("signature expiration time (default is start-time + 30 days).");
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('e'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      OptionBuilder.hasArg();
 | 
				
			||||||
 | 
					      OptionBuilder.withArgName("outfile");
 | 
				
			||||||
 | 
					      OptionBuilder.withDescription("file the signed rrset is written to.");
 | 
				
			||||||
 | 
					      opts.addOption(OptionBuilder.create('f'));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    public void parseCommandLine(String[] args)
 | 
				
			||||||
     * Verify the generated signatures.
 | 
					        throws org.apache.commons.cli.ParseException, ParseException, IOException
 | 
				
			||||||
     * 
 | 
					    {
 | 
				
			||||||
     * @param zonename
 | 
					      CommandLineParser cli_parser = new PosixParser();
 | 
				
			||||||
     *            the origin name of the zone.
 | 
					      CommandLine cli = cli_parser.parse(opts, args);
 | 
				
			||||||
     * @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 verifySigs(Name zonename, List records, List keypairs) {
 | 
					 | 
				
			||||||
        boolean secure = true;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DnsSecVerifier verifier = new DnsSecVerifier();
 | 
					      String optstr = null;
 | 
				
			||||||
 | 
					      if (cli.hasOption('h')) usage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (Iterator i = keypairs.iterator(); i.hasNext();) {
 | 
					      Logger rootLogger = Logger.getLogger("");
 | 
				
			||||||
            verifier.addTrustedKey((DnsKeyPair) i.next());
 | 
					      if (cli.hasOption('v'))
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        int value = parseInt(cli.getOptionValue('v'), -1);
 | 
				
			||||||
 | 
					        switch (value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          case 0:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.OFF);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 1:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.SEVERE);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 2:
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.WARNING);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 3:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.INFO);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 4:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.CONFIG);
 | 
				
			||||||
 | 
					          case 5:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.FINE);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 6:
 | 
				
			||||||
 | 
					            rootLogger.setLevel(Level.ALL);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // I hate java.util.logging, btw.
 | 
				
			||||||
 | 
					      for (Handler h : rootLogger.getHandlers())
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        h.setLevel(rootLogger.getLevel());
 | 
				
			||||||
 | 
					        h.setFormatter(new BareLogFormatter());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        verifier.setVerifyAllSigs(true);
 | 
					      if (cli.hasOption('a')) verifySigs = true;
 | 
				
			||||||
 | 
					      if (cli.hasOption('m')) org.xbill.DNS.Options.set("multiline");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        List rrsets = SignUtils.assembleIntoRRsets(records);
 | 
					      if ((optstr = cli.getOptionValue('D')) != null)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
        for (Iterator i = rrsets.iterator(); i.hasNext();) {
 | 
					        keyDirectory = new File(optstr);
 | 
				
			||||||
            RRset rrset = (RRset) i.next();
 | 
					        if (!keyDirectory.isDirectory())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            // skip unsigned rrsets.
 | 
					          System.err.println("error: " + optstr + " is not a directory");
 | 
				
			||||||
            if (!rrset.sigs().hasNext()) continue;
 | 
					          usage();
 | 
				
			||||||
 | 
					 | 
				
			||||||
            int result = verifier.verify(rrset, null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (result != DNSSEC.Secure) {
 | 
					 | 
				
			||||||
                log.fine("Signatures did not verify for RRset: (" + result
 | 
					 | 
				
			||||||
                        + "): " + rrset);
 | 
					 | 
				
			||||||
                secure = false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return secure;
 | 
					      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');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      String[] files = cli.getArgs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (files.length < 1)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        System.err.println("error: missing zone file and/or key files");
 | 
				
			||||||
 | 
					        usage();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      inputfile = files[0];
 | 
				
			||||||
 | 
					      if (files.length > 1)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        keyFiles = new String[files.length - 1];
 | 
				
			||||||
 | 
					        System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /** Print out the usage and help statements, then quit. */
 | 
				
			||||||
     * Load the key pairs from the key files.
 | 
					    private void usage()
 | 
				
			||||||
     * 
 | 
					    {
 | 
				
			||||||
     * @param keyfiles
 | 
					      HelpFormatter f = new HelpFormatter();
 | 
				
			||||||
     *            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<DnsKeyPair> getKeys(String[] keyfiles, int start_index,
 | 
					 | 
				
			||||||
                                            File inDirectory)
 | 
					 | 
				
			||||||
            throws IOException {
 | 
					 | 
				
			||||||
        if (keyfiles == null) return null;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int len = keyfiles.length - start_index;
 | 
					      PrintWriter out = new PrintWriter(System.err);
 | 
				
			||||||
        if (len <= 0) return null;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ArrayList<DnsKeyPair> keys = new ArrayList<DnsKeyPair>(len);
 | 
					      // print our own usage statement:
 | 
				
			||||||
 | 
					      f.printHelp(out, 75, "jdnssec-signrrset [..options..] "
 | 
				
			||||||
 | 
					                      + "rrset_file key_file [key_file ...]", null, opts,
 | 
				
			||||||
 | 
					                  HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD,
 | 
				
			||||||
 | 
					                  "\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (int i = start_index; i < keyfiles.length; i++) {
 | 
					      out.flush();
 | 
				
			||||||
            DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
 | 
					      System.exit(64);
 | 
				
			||||||
            if (k != null) keys.add(k);
 | 
					    }
 | 
				
			||||||
        }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return keys;
 | 
					  /**
 | 
				
			||||||
 | 
					   * 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 verifySigs(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);
 | 
				
			||||||
     * 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);
 | 
					    List rrsets = SignUtils.assembleIntoRRsets(records);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (duration.startsWith("+")) {
 | 
					    for (Iterator i = rrsets.iterator(); i.hasNext();)
 | 
				
			||||||
            long offset = (long) parseInt(duration.substring(1), 0) * 1000;
 | 
					    {
 | 
				
			||||||
            return new Date(start.getTime() + offset);
 | 
					      RRset rrset = (RRset) i.next();
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
 | 
					      // skip unsigned rrsets.
 | 
				
			||||||
        dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
 | 
					      if (!rrset.sigs().hasNext()) continue;
 | 
				
			||||||
        return dateFormatter.parse(duration);
 | 
					
 | 
				
			||||||
 | 
					      int result = verifier.verify(rrset, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (result != DNSSEC.Secure)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset);
 | 
				
			||||||
 | 
					        secure = false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void execute(CLIState state) throws Exception {
 | 
					    return secure;
 | 
				
			||||||
        // Read in the zone
 | 
					  }
 | 
				
			||||||
        List records = ZoneUtils.readZoneFile(state.inputfile, null);
 | 
					 | 
				
			||||||
        if (records == null || records.size() == 0) {
 | 
					 | 
				
			||||||
            System.err.println("error: empty RRset file");
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // Construct the RRset. Complain if the records in the input file
 | 
					 | 
				
			||||||
        // consist of more than one RRset.
 | 
					 | 
				
			||||||
        RRset rrset = null;
 | 
					 | 
				
			||||||
        for (Iterator i = records.iterator(); i.hasNext();) {
 | 
					 | 
				
			||||||
            Record r = (Record) i.next();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // skip RRSIGs
 | 
					  /**
 | 
				
			||||||
            if (r.getType() == Type.RRSIG || r.getType() == Type.SIG) {
 | 
					   * Load the key pairs from the key files.
 | 
				
			||||||
                continue;
 | 
					   *
 | 
				
			||||||
            }
 | 
					   * @param keyfiles
 | 
				
			||||||
            
 | 
					   *          a string array containing the base names or paths of the keys
 | 
				
			||||||
            // Handle the first record.
 | 
					   *          to be loaded.
 | 
				
			||||||
            if (rrset == null) {
 | 
					   * @param start_index
 | 
				
			||||||
                rrset = new RRset();
 | 
					   *          the starting index of keyfiles string array to use. This
 | 
				
			||||||
                rrset.addRR(r);
 | 
					   *          allows us to use the straight command line argument array.
 | 
				
			||||||
                continue;
 | 
					   * @param inDirectory
 | 
				
			||||||
            }
 | 
					   *          the directory to look in (may be null).
 | 
				
			||||||
            // Ensure that the remaining records all belong to the same rrset.
 | 
					   * @return a list of keypair objects.
 | 
				
			||||||
            if (rrset.getName().equals(r.getName())
 | 
					   */
 | 
				
			||||||
                    && rrset.getType() == r.getType()
 | 
					  private static List<DnsKeyPair> getKeys(String[] keyfiles, int start_index,
 | 
				
			||||||
                    && rrset.getDClass() == r.getDClass()) {
 | 
					                                          File inDirectory) throws IOException
 | 
				
			||||||
                rrset.addRR(r);
 | 
					  {
 | 
				
			||||||
            } else {
 | 
					    if (keyfiles == null) return null;
 | 
				
			||||||
                System.err.println("Records do not all belong to the same RRset.");
 | 
					 | 
				
			||||||
                state.usage();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (rrset.size() == 0) {
 | 
					    int len = keyfiles.length - start_index;
 | 
				
			||||||
            System.err.println("No records found in inputfile.");
 | 
					    if (len <= 0) return null;
 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Load the key pairs.
 | 
					    ArrayList<DnsKeyPair> keys = new ArrayList<DnsKeyPair>(len);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (state.keyFiles.length == 0) {
 | 
					 | 
				
			||||||
            System.err.println("error: at least one keyfile must be specified");
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        List<DnsKeyPair> keypairs = getKeys(state.keyFiles, 0,
 | 
					 | 
				
			||||||
                                            state.keyDirectory);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Make sure that all the keypairs have the same name.
 | 
					 | 
				
			||||||
        // This will be used as the zone name, too.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Name keysetName = null;
 | 
					 | 
				
			||||||
        for (DnsKeyPair pair : keypairs) {
 | 
					 | 
				
			||||||
            if (keysetName == null) {
 | 
					 | 
				
			||||||
                keysetName = pair.getDNSKEYName();
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (!pair.getDNSKEYName().equals(keysetName)) {
 | 
					 | 
				
			||||||
                System.err.println("Keys do not all have the same name.");
 | 
					 | 
				
			||||||
                state.usage();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // default the output file, if not set.
 | 
					 | 
				
			||||||
        if (state.outputfile == null && !state.inputfile.equals("-")) {
 | 
					 | 
				
			||||||
            state.outputfile = state.inputfile + ".signed";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        JCEDnsSecSigner signer = new JCEDnsSecSigner();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        List sigs = signer.signRRset(rrset, keypairs, state.start,
 | 
					 | 
				
			||||||
                                     state.expire);
 | 
					 | 
				
			||||||
        for (Iterator i = sigs.iterator(); i.hasNext();) {
 | 
					 | 
				
			||||||
            rrset.addRR((Record) i.next());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // write out the signed RRset
 | 
					 | 
				
			||||||
        List signed_records = new ArrayList();
 | 
					 | 
				
			||||||
        for (Iterator i = rrset.rrs(); i.hasNext();) {
 | 
					 | 
				
			||||||
            signed_records.add(i.next());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        for (Iterator i = rrset.sigs(); i.hasNext();) {
 | 
					 | 
				
			||||||
            signed_records.add(i.next());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // write out the signed zone
 | 
					 | 
				
			||||||
        ZoneUtils.writeZoneFile(signed_records, state.outputfile);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (state.verifySigs) {
 | 
					 | 
				
			||||||
            log.fine("verifying generated signatures");
 | 
					 | 
				
			||||||
            boolean res = verifySigs(keysetName, 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.");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = start_index; i < keyfiles.length; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
 | 
				
			||||||
 | 
					      if (k != null) keys.add(k);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void main(String[] args) {
 | 
					    return keys;
 | 
				
			||||||
        CLIState state = new CLIState();
 | 
					  }
 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            state.parseCommandLine(args);
 | 
					 | 
				
			||||||
        } catch (UnrecognizedOptionException e) {
 | 
					 | 
				
			||||||
            System.err.println("error: unknown option encountered: "
 | 
					 | 
				
			||||||
                    + e.getMessage());
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        } catch (AlreadySelectedException e) {
 | 
					 | 
				
			||||||
            System.err.println("error: mutually exclusive options have "
 | 
					 | 
				
			||||||
                    + "been selected:\n     " + e.getMessage());
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        } catch (Exception e) {
 | 
					 | 
				
			||||||
            System.err.println("error: unknown command line parsing exception:");
 | 
					 | 
				
			||||||
            e.printStackTrace();
 | 
					 | 
				
			||||||
            state.usage();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        log = Logger.getLogger(SignRRset.class.toString());
 | 
					  /**
 | 
				
			||||||
 | 
					   * 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					      duration = duration.substring(3);
 | 
				
			||||||
            execute(state);
 | 
					 | 
				
			||||||
        } catch (Exception e) {
 | 
					 | 
				
			||||||
            e.printStackTrace();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public static void execute(CLIState state) throws Exception
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    // Read in the zone
 | 
				
			||||||
 | 
					    List records = ZoneUtils.readZoneFile(state.inputfile, null);
 | 
				
			||||||
 | 
					    if (records == null || records.size() == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: empty RRset file");
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Construct the RRset. Complain if the records in the input file
 | 
				
			||||||
 | 
					    // consist of more than one RRset.
 | 
				
			||||||
 | 
					    RRset rrset = null;
 | 
				
			||||||
 | 
					    for (Iterator i = records.iterator(); i.hasNext();)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      Record r = (Record) i.next();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // skip RRSIGs
 | 
				
			||||||
 | 
					      if (r.getType() == Type.RRSIG || r.getType() == Type.SIG)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Handle the first record.
 | 
				
			||||||
 | 
					      if (rrset == null)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        rrset = new RRset();
 | 
				
			||||||
 | 
					        rrset.addRR(r);
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Ensure that the remaining records all belong to the same rrset.
 | 
				
			||||||
 | 
					      if (rrset.getName().equals(r.getName()) && rrset.getType() == r.getType()
 | 
				
			||||||
 | 
					          && rrset.getDClass() == r.getDClass())
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        rrset.addRR(r);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        System.err.println("Records do not all belong to the same RRset.");
 | 
				
			||||||
 | 
					        state.usage();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rrset.size() == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("No records found in inputfile.");
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Load the key pairs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (state.keyFiles.length == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: at least one keyfile must be specified");
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    List<DnsKeyPair> keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Make sure that all the keypairs have the same name.
 | 
				
			||||||
 | 
					    // This will be used as the zone name, too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Name keysetName = null;
 | 
				
			||||||
 | 
					    for (DnsKeyPair pair : keypairs)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      if (keysetName == null)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        keysetName = pair.getDNSKEYName();
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!pair.getDNSKEYName().equals(keysetName))
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        System.err.println("Keys do not all have the same name.");
 | 
				
			||||||
 | 
					        state.usage();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // default the output file, if not set.
 | 
				
			||||||
 | 
					    if (state.outputfile == null && !state.inputfile.equals("-"))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      state.outputfile = state.inputfile + ".signed";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JCEDnsSecSigner signer = new JCEDnsSecSigner();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    List sigs = signer.signRRset(rrset, keypairs, state.start, state.expire);
 | 
				
			||||||
 | 
					    for (Iterator i = sigs.iterator(); i.hasNext();)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      rrset.addRR((Record) i.next());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // write out the signed RRset
 | 
				
			||||||
 | 
					    List signed_records = new ArrayList();
 | 
				
			||||||
 | 
					    for (Iterator i = rrset.rrs(); i.hasNext();)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      signed_records.add(i.next());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (Iterator i = rrset.sigs(); i.hasNext();)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      signed_records.add(i.next());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // write out the signed zone
 | 
				
			||||||
 | 
					    ZoneUtils.writeZoneFile(signed_records, state.outputfile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (state.verifySigs)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      log.fine("verifying generated signatures");
 | 
				
			||||||
 | 
					      boolean res = verifySigs(keysetName, 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)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    CLIState state = new CLIState();
 | 
				
			||||||
 | 
					    try
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      state.parseCommandLine(args);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (UnrecognizedOptionException e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: unknown option encountered: " + e.getMessage());
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (AlreadySelectedException e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: mutually exclusive options have "
 | 
				
			||||||
 | 
					          + "been selected:\n     " + e.getMessage());
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (Exception e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      System.err.println("error: unknown command line parsing exception:");
 | 
				
			||||||
 | 
					      e.printStackTrace();
 | 
				
			||||||
 | 
					      state.usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log = Logger.getLogger(SignRRset.class.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      execute(state);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (Exception e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      e.printStackTrace();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user