8138766: New default -sigalg for keytool
authorweijun
Fri, 20 May 2016 11:20:49 +0800
changeset 38439 8a3871cd7fca
parent 38438 6e6b1c38fdc0
child 38440 9e77c5b81def
8138766: New default -sigalg for keytool Reviewed-by: mullan
jdk/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java
jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java
jdk/test/sun/security/tools/keytool/DefaultSignatureAlgorithm.java
--- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java	Fri May 20 11:15:05 2016 +0800
+++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java	Fri May 20 11:20:49 2016 +0800
@@ -67,7 +67,9 @@
      *
      * @param keyType type of key, e.g. "RSA", "DSA"
      * @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA",
-     *          "MD2WithRSA", "SHAwithDSA".
+     *          "MD2WithRSA", "SHAwithDSA". If set to null, a default
+     *          algorithm matching the private key will be chosen after
+     *          the first keypair is generated.
      * @exception NoSuchAlgorithmException on unrecognized algorithms.
      */
     public CertAndKeyGen (String keyType, String sigAlg)
@@ -83,7 +85,9 @@
      *
      * @param keyType type of key, e.g. "RSA", "DSA"
      * @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA",
-     *          "MD2WithRSA", "SHAwithDSA".
+     *          "MD2WithRSA", "SHAwithDSA". If set to null, a default
+     *          algorithm matching the private key will be chosen after
+     *          the first keypair is generated.
      * @param providerName name of the provider
      * @exception NoSuchAlgorithmException on unrecognized algorithms.
      * @exception NoSuchProviderException on unrecognized providers.
@@ -161,9 +165,17 @@
             throw new IllegalArgumentException("Public key format is "
                 + publicKey.getFormat() + ", must be X.509");
         }
+
+        if (sigAlg == null) {
+            sigAlg = AlgorithmId.getDefaultSigAlgForKey(privateKey);
+            if (sigAlg == null) {
+                throw new IllegalArgumentException(
+                        "Cannot derive signature algorithm from "
+                                + privateKey.getAlgorithm());
+            }
+        }
     }
 
-
     /**
      * Returns the public key of the generated key pair if it is of type
      * <code>X509Key</code>, or null if the public key is of a different type.
--- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Fri May 20 11:15:05 2016 +0800
+++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Fri May 20 11:20:49 2016 +0800
@@ -54,7 +54,6 @@
 import java.util.*;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
-import java.lang.reflect.Constructor;
 import java.math.BigInteger;
 import java.net.URI;
 import java.net.URL;
@@ -1238,7 +1237,7 @@
         PrivateKey privateKey =
                 (PrivateKey)recoverKey(alias, storePass, keyPass).fst;
         if (sigAlgName == null) {
-            sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm());
+            sigAlgName = getCompatibleSigAlgName(privateKey);
         }
         Signature signature = Signature.getInstance(sigAlgName);
         signature.initSign(privateKey);
@@ -1328,7 +1327,7 @@
         PrivateKey privateKey =
                 (PrivateKey)recoverKey(alias, storePass, keyPass).fst;
         if (sigAlgName == null) {
-            sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm());
+            sigAlgName = getCompatibleSigAlgName(privateKey);
         }
 
         X509CRLEntry[] badCerts = new X509CRLEntry[ids.size()];
@@ -1387,7 +1386,7 @@
 
         // Construct a Signature object, so that we can sign the request
         if (sigAlgName == null) {
-            sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm());
+            sigAlgName = getCompatibleSigAlgName(privKey);
         }
 
         Signature signature = Signature.getInstance(sigAlgName);
@@ -1619,19 +1618,17 @@
      * If no signature algorithm was specified at the command line,
      * we choose one that is compatible with the selected private key
      */
-    private static String getCompatibleSigAlgName(String keyAlgName)
+    private static String getCompatibleSigAlgName(PrivateKey key)
             throws Exception {
-        if ("DSA".equalsIgnoreCase(keyAlgName)) {
-            return "SHA256WithDSA";
-        } else if ("RSA".equalsIgnoreCase(keyAlgName)) {
-            return "SHA256WithRSA";
-        } else if ("EC".equalsIgnoreCase(keyAlgName)) {
-            return "SHA256withECDSA";
+        String result = AlgorithmId.getDefaultSigAlgForKey(key);
+        if (result != null) {
+            return result;
         } else {
             throw new Exception(rb.getString
                     ("Cannot.derive.signature.algorithm"));
         }
     }
+
     /**
      * Creates a new key pair and self-signed certificate.
      */
@@ -1658,9 +1655,6 @@
             throw new Exception(form.format(source));
         }
 
-        if (sigAlgName == null) {
-            sigAlgName = getCompatibleSigAlgName(keyAlgName);
-        }
         CertAndKeyGen keypair =
                 new CertAndKeyGen(keyAlgName, sigAlgName, providerName);
 
@@ -2526,7 +2520,7 @@
 
         // Determine the signature algorithm
         if (sigAlgName == null) {
-            sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm());
+            sigAlgName = getCompatibleSigAlgName(privKey);
         }
 
         // Get the old certificate
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/tools/keytool/DefaultSignatureAlgorithm.java	Fri May 20 11:20:49 2016 +0800
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8138766
+ * @summary New default -sigalg for keytool
+ * @modules java.base/sun.security.tools.keytool
+ */
+
+import sun.security.tools.keytool.Main;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+
+public class DefaultSignatureAlgorithm {
+
+    private static int counter = 0;
+
+    public static void main(String[] args) throws Exception {
+
+        // Calculating large RSA keys are too slow.
+        run("RSA", 1024, null, "SHA256withRSA");
+        run("RSA", 3072, null, "SHA256withRSA");
+        run("RSA", 3073, null, "SHA384withRSA");
+
+        run("DSA", 1024, null, "SHA256withDSA");
+        run("DSA", 3072, null, "SHA256withDSA");
+
+        run("EC", 192, null, "SHA256withECDSA");
+        run("EC", 384, null, "SHA384withECDSA");
+        run("EC", 571, null, "SHA512withECDSA");
+
+        // If you specify one, it will be used.
+        run("EC", 571, "SHA256withECDSA", "SHA256withECDSA");
+    }
+
+    private static void run(String keyAlg, int keySize,
+                    String sigAlg, String expectedSigAlg) throws Exception {
+        String alias = keyAlg + keySize + (counter++);
+        String cmd = "-keystore ks -storepass changeit" +
+                " -keypass changeit -alias " + alias +
+                " -keyalg " + keyAlg + " -keysize " + keySize +
+                " -genkeypair -dname CN=" + alias + " -debug";
+        if (sigAlg != null) {
+            cmd += " -sigalg " + sigAlg;
+        }
+        Main.main(cmd.split(" "));
+
+        KeyStore ks = KeyStore.getInstance(
+                new File("ks"), "changeit".toCharArray());
+        X509Certificate cert = (X509Certificate)ks.getCertificate(alias);
+        String actualSigAlg = cert.getSigAlgName();
+        if (!actualSigAlg.equals(expectedSigAlg)) {
+            throw new Exception("Failure at " + alias + ": expected "
+                    + expectedSigAlg + ", actually " + actualSigAlg);
+        }
+    }
+}