8213400: Support choosing group name in keytool keypair generation

Reviewed-by: apetcher, xuelei
This commit is contained in:
Weijun Wang 2018-11-14 08:46:25 +08:00
parent 761710ffab
commit 65dc116bf6
4 changed files with 188 additions and 41 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2018, 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
@ -30,6 +30,8 @@ import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.NamedParameterSpec;
import java.util.Date;
import sun.security.pkcs10.PKCS10;
@ -48,8 +50,7 @@ import sun.security.x509.*;
* parameters, such as DSS/DSA. Some sites' Certificate Authorities
* adopt fixed algorithm parameters, which speeds up some operations
* including key generation and signing. <em>At this time, this interface
* does not provide a way to provide such algorithm parameters, e.g.
* by providing the CA certificate which includes those parameters.</em>
* supports initializing with a named group.</em>
*
* <P>Also, note that at this time only signature-capable keys may be
* acquired through this interface. Diffie-Hellman keys, used for secure
@ -77,6 +78,7 @@ public final class CertAndKeyGen {
{
keyGen = KeyPairGenerator.getInstance(keyType);
this.sigAlg = sigAlg;
this.keyType = keyType;
}
/**
@ -106,6 +108,7 @@ public final class CertAndKeyGen {
}
}
this.sigAlg = sigAlg;
this.keyType = keyType;
}
/**
@ -121,41 +124,58 @@ public final class CertAndKeyGen {
prng = generator;
}
// want "public void generate (X509Certificate)" ... inherit DSA/D-H param
/**
* Generates a random public/private key pair, with a given key
* size. Different algorithms provide different degrees of security
* for the same key size, because of the "work factor" involved in
* brute force attacks. As computers become faster, it becomes
* easier to perform such attacks. Small keys are to be avoided.
*
* <P>Note that not all values of "keyBits" are valid for all
* algorithms, and not all public key algorithms are currently
* supported for use in X.509 certificates. If the algorithm
* you specified does not produce X.509 compatible keys, an
* invalid key exception is thrown.
*
* @param keyBits the number of bits in the keys.
* @exception InvalidKeyException if the environment does not
* provide X.509 public keys for this signature algorithm.
*/
public void generate (int keyBits)
throws InvalidKeyException
{
KeyPair pair;
public void generate(String name) {
try {
if (prng == null) {
prng = new SecureRandom();
}
keyGen.initialize(keyBits, prng);
pair = keyGen.generateKeyPair();
try {
keyGen.initialize(new NamedParameterSpec(name), prng);
} catch (InvalidAlgorithmParameterException e) {
if (keyType.equalsIgnoreCase("EC")) {
// EC has another NamedParameterSpec
keyGen.initialize(new ECGenParameterSpec(name), prng);
} else {
throw e;
}
}
} catch (Exception e) {
throw new IllegalArgumentException(e.getMessage());
}
generateInternal();
}
// want "public void generate (X509Certificate)" ... inherit DSA/D-H param
public void generate(int keyBits) {
if (keyBits != -1) {
try {
if (prng == null) {
prng = new SecureRandom();
}
keyGen.initialize(keyBits, prng);
} catch (Exception e) {
throw new IllegalArgumentException(e.getMessage());
}
}
generateInternal();
}
/**
* Generates a random public/private key pair.
*
* <P>Note that not all public key algorithms are currently
* supported for use in X.509 certificates. If the algorithm
* you specified does not produce X.509 compatible keys, an
* invalid key exception is thrown.
*
* @exception IllegalArgumentException if the environment does not
* provide X.509 public keys for this signature algorithm.
*/
private void generateInternal() {
KeyPair pair = keyGen.generateKeyPair();
publicKey = pair.getPublic();
privateKey = pair.getPrivate();
@ -333,6 +353,7 @@ public final class CertAndKeyGen {
}
private SecureRandom prng;
private String keyType;
private String sigAlg;
private KeyPairGenerator keyGen;
private PublicKey publicKey;

View file

@ -28,13 +28,13 @@ package sun.security.tools.keytool;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.AlgorithmParameters;
import java.security.CodeSigner;
import java.security.CryptoPrimitive;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.Key;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.Signature;
@ -68,6 +68,7 @@ import java.security.cert.X509CRLSelector;
import javax.security.auth.x500.X500Principal;
import java.util.Base64;
import sun.security.util.ECKeySizeParameterSpec;
import sun.security.util.KeyUtil;
import sun.security.util.ObjectIdentifier;
import sun.security.pkcs10.PKCS10;
@ -116,6 +117,7 @@ public final class Main {
private String keyAlgName = null;
private boolean verbose = false;
private int keysize = -1;
private String groupName = null;
private boolean rfc = false;
private long validity = (long)90;
private String alias = null;
@ -202,7 +204,7 @@ public final class Main {
STORETYPE, PROVIDERNAME, ADDPROVIDER, PROVIDERCLASS,
PROVIDERPATH, V, PROTECTED),
GENKEYPAIR("Generates.a.key.pair",
ALIAS, KEYALG, KEYSIZE, SIGALG, DESTALIAS, DNAME,
ALIAS, KEYALG, KEYSIZE, CURVENAME, SIGALG, DESTALIAS, DNAME,
STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE,
STOREPASS, STORETYPE, PROVIDERNAME, ADDPROVIDER,
PROVIDERCLASS, PROVIDERPATH, V, PROTECTED),
@ -314,6 +316,7 @@ public final class Main {
// in the optionsSet.contains() block in parseArgs().
enum Option {
ALIAS("alias", "<alias>", "alias.name.of.the.entry.to.process"),
CURVENAME("groupname", "<name>", "groupname.option.help"),
DESTALIAS("destalias", "<alias>", "destination.alias"),
DESTKEYPASS("destkeypass", "<arg>", "destination.key.password"),
DESTKEYSTORE("destkeystore", "<keystore>", "destination.keystore.name"),
@ -586,6 +589,8 @@ public final class Main {
dname = args[++i];
} else if (collator.compare(flags, "-keysize") == 0) {
keysize = Integer.parseInt(args[++i]);
} else if (collator.compare(flags, "-groupname") == 0) {
groupName = args[++i];
} else if (collator.compare(flags, "-keyalg") == 0) {
keyAlgName = args[++i];
} else if (collator.compare(flags, "-sigalg") == 0) {
@ -1119,7 +1124,7 @@ public final class Main {
if (keyAlgName == null) {
keyAlgName = "DSA";
}
doGenKeyPair(alias, dname, keyAlgName, keysize, sigAlgName);
doGenKeyPair(alias, dname, keyAlgName, keysize, groupName, sigAlgName);
kssave = true;
} else if (command == GENSECKEY) {
if (keyAlgName == null) {
@ -1793,16 +1798,28 @@ public final class Main {
* Creates a new key pair and self-signed certificate.
*/
private void doGenKeyPair(String alias, String dname, String keyAlgName,
int keysize, String sigAlgName)
int keysize, String groupName, String sigAlgName)
throws Exception
{
if (keysize == -1) {
if ("EC".equalsIgnoreCase(keyAlgName)) {
keysize = SecurityProviderConstants.DEF_EC_KEY_SIZE;
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
keysize = SecurityProviderConstants.DEF_RSA_KEY_SIZE;
} else if ("DSA".equalsIgnoreCase(keyAlgName)) {
keysize = SecurityProviderConstants.DEF_DSA_KEY_SIZE;
if (groupName != null) {
if (keysize != -1) {
throw new Exception(rb.getString("groupname.keysize.coexist"));
}
} else {
if (keysize == -1) {
if ("EC".equalsIgnoreCase(keyAlgName)) {
keysize = SecurityProviderConstants.DEF_EC_KEY_SIZE;
} else if ("RSA".equalsIgnoreCase(keyAlgName)) {
keysize = SecurityProviderConstants.DEF_RSA_KEY_SIZE;
} else if ("DSA".equalsIgnoreCase(keyAlgName)) {
keysize = SecurityProviderConstants.DEF_DSA_KEY_SIZE;
}
} else {
if ("EC".equalsIgnoreCase(keyAlgName)) {
weakWarnings.add(String.format(
rb.getString("deprecate.keysize.for.ec"),
ecGroupNameForSize(keysize)));
}
}
}
@ -1829,7 +1846,13 @@ public final class Main {
x500Name = new X500Name(dname);
}
keypair.generate(keysize);
if (groupName != null) {
keypair.generate(groupName);
} else {
// This covers keysize both specified and unspecified
keypair.generate(keysize);
}
PrivateKey privKey = keypair.getPrivateKey();
CertificateExtensions ext = createV3Extensions(
@ -1861,6 +1884,13 @@ public final class Main {
keyStore.setKeyEntry(alias, privKey, keyPass, chain);
}
private String ecGroupNameForSize(int size) throws Exception {
AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
ap.init(new ECKeySizeParameterSpec(size));
// The following line assumes the toString value is "name (oid)"
return ap.toString().split(" ")[0];
}
/**
* Clones an entry
* @param orig original alias

View file

@ -99,6 +99,8 @@ public class Resources extends java.util.ListResourceBundle {
// keytool: help: options
{"alias.name.of.the.entry.to.process",
"alias name of the entry to process"}, //-alias
{"groupname.option.help",
"Group name. For example, an Elliptic Curve name."}, //-groupname
{"destination.alias",
"destination alias"}, //-destalias
{"destination.key.password",
@ -290,6 +292,10 @@ public class Resources extends java.util.ListResourceBundle {
"Alias <{0}> does not exist"},
{"Alias.alias.has.no.certificate",
"Alias <{0}> has no certificate"},
{"groupname.keysize.coexist",
"Cannot specify both -groupname and -keysize"},
{"deprecate.keysize.for.ec",
"Specifying -keysize for generating EC keys is deprecated, please use \"-groupname %s\" instead."},
{"Key.pair.not.generated.alias.alias.already.exists",
"Key pair not generated, alias <{0}> already exists"},
{"Generating.keysize.bit.keyAlgName.key.pair.and.self.signed.certificate.sigAlgName.with.a.validity.of.validality.days.for",