Path: blob/master/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java
41161 views
/*1* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.tools.keytool;2627import java.io.IOException;28import java.security.cert.X509Certificate;29import java.security.cert.CertificateException;30import java.security.cert.CertificateEncodingException;31import java.security.*;32import java.security.spec.ECGenParameterSpec;33import java.security.spec.NamedParameterSpec;34import java.util.Date;3536import sun.security.pkcs10.PKCS10;37import sun.security.util.SignatureUtil;38import sun.security.x509.*;3940/**41* Generate a pair of keys, and provide access to them. This class is42* provided primarily for ease of use.43*44* <P>This provides some simple certificate management functionality.45* Specifically, it allows you to create self-signed X.509 certificates46* as well as PKCS 10 based certificate signing requests.47*48* <P>Keys for some public key signature algorithms have algorithm49* parameters, such as DSS/DSA. Some sites' Certificate Authorities50* adopt fixed algorithm parameters, which speeds up some operations51* including key generation and signing. <em>At this time, this interface52* supports initializing with a named group.</em>53*54* <P>Also, note that at this time only signature-capable keys may be55* acquired through this interface. Diffie-Hellman keys, used for secure56* key exchange, may be supported later.57*58* @author David Brownell59* @author Hemma Prafullchandra60* @see PKCS1061* @see X509CertImpl62*/63public final class CertAndKeyGen {64/**65* Creates a CertAndKeyGen object for a particular key type66* and signature algorithm.67*68* @param keyType type of key, e.g. "RSA", "DSA"69* @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA",70* "MD2WithRSA", "SHAwithDSA". If set to null, a default71* algorithm matching the private key will be chosen after72* the first keypair is generated.73* @exception NoSuchAlgorithmException on unrecognized algorithms.74*/75public CertAndKeyGen (String keyType, String sigAlg)76throws NoSuchAlgorithmException77{78keyGen = KeyPairGenerator.getInstance(keyType);79this.sigAlg = sigAlg;80this.keyType = keyType;81}8283/**84* @see #CertAndKeyGen(String, String, String, PrivateKey, X500Name)85*/86public CertAndKeyGen (String keyType, String sigAlg, String providerName)87throws NoSuchAlgorithmException, NoSuchProviderException88{89this(keyType, sigAlg, providerName, null, null);90}9192/**93* Creates a CertAndKeyGen object for a particular key type,94* signature algorithm, and provider. The newly generated cert will95* be signed by the signer's private key when it is provided.96*97* @param keyType type of key, e.g. "RSA", "DSA", "X25519", "DH", etc.98* @param sigAlg name of the signature algorithm, e.g. "SHA384WithRSA",99* "SHA256withDSA", etc. If set to null, a default100* algorithm matching the private key or signer's private101* key will be chosen after the first keypair is generated.102* @param providerName name of the provider103* @param signerPrivateKey (optional) signer's private key104* @param signerSubjectName (optional) signer's subject name105* @exception NoSuchAlgorithmException on unrecognized algorithms.106* @exception NoSuchProviderException on unrecognized providers.107*/108public CertAndKeyGen(String keyType, String sigAlg, String providerName,109PrivateKey signerPrivateKey, X500Name signerSubjectName)110throws NoSuchAlgorithmException, NoSuchProviderException111{112if (providerName == null) {113keyGen = KeyPairGenerator.getInstance(keyType);114} else {115try {116keyGen = KeyPairGenerator.getInstance(keyType, providerName);117} catch (Exception e) {118// try first available provider instead119keyGen = KeyPairGenerator.getInstance(keyType);120}121}122this.sigAlg = sigAlg;123this.keyType = keyType;124this.signerPrivateKey = signerPrivateKey;125this.signerSubjectName = signerSubjectName;126this.signerFlag = signerPrivateKey != null;127}128129/**130* Sets the source of random numbers used when generating keys.131* If you do not provide one, a system default facility is used.132* You may wish to provide your own source of random numbers133* to get a reproducible sequence of keys and signatures, or134* because you may be able to take advantage of strong sources135* of randomness/entropy in your environment.136*/137public void setRandom (SecureRandom generator)138{139prng = generator;140}141142public void generate(String name) {143try {144if (prng == null) {145prng = new SecureRandom();146}147try {148keyGen.initialize(new NamedParameterSpec(name), prng);149} catch (InvalidAlgorithmParameterException e) {150if (keyType.equalsIgnoreCase("EC")) {151// EC has another NamedParameterSpec152keyGen.initialize(new ECGenParameterSpec(name), prng);153} else {154throw e;155}156}157158} catch (Exception e) {159throw new IllegalArgumentException(e.getMessage());160}161generateInternal();162}163164// want "public void generate (X509Certificate)" ... inherit DSA/D-H param165166public void generate(int keyBits) {167if (keyBits != -1) {168try {169if (prng == null) {170prng = new SecureRandom();171}172keyGen.initialize(keyBits, prng);173174} catch (Exception e) {175throw new IllegalArgumentException(e.getMessage());176}177}178generateInternal();179}180181/**182* Generates a random public/private key pair.183*184* <P>Note that not all public key algorithms are currently185* supported for use in X.509 certificates. If the algorithm186* you specified does not produce X.509 compatible keys, an187* invalid key exception is thrown.188*189* @exception IllegalArgumentException if the environment does not190* provide X.509 public keys for this signature algorithm.191*/192private void generateInternal() {193KeyPair pair = keyGen.generateKeyPair();194publicKey = pair.getPublic();195privateKey = pair.getPrivate();196197// publicKey's format must be X.509 otherwise198// the whole CertGen part of this class is broken.199if (!"X.509".equalsIgnoreCase(publicKey.getFormat())) {200throw new IllegalArgumentException("Public key format is "201+ publicKey.getFormat() + ", must be X.509");202}203204if (sigAlg == null) {205if (signerFlag) {206sigAlg = SignatureUtil.getDefaultSigAlgForKey(signerPrivateKey);207if (sigAlg == null) {208throw new IllegalArgumentException(209"Cannot derive signature algorithm from "210+ signerPrivateKey.getAlgorithm());211}212} else {213sigAlg = SignatureUtil.getDefaultSigAlgForKey(privateKey);214if (sigAlg == null) {215throw new IllegalArgumentException(216"Cannot derive signature algorithm from "217+ privateKey.getAlgorithm());218}219}220}221}222223/**224* Returns the public key of the generated key pair if it is of type225* <code>X509Key</code>, or null if the public key is of a different type.226*227* XXX Note: This behaviour is needed for backwards compatibility.228* What this method really should return is the public key of the229* generated key pair, regardless of whether or not it is an instance of230* <code>X509Key</code>. Accordingly, the return type of this method231* should be <code>PublicKey</code>.232*/233public X509Key getPublicKey()234{235if (!(publicKey instanceof X509Key)) {236return null;237}238return (X509Key)publicKey;239}240241/**242* Always returns the public key of the generated key pair. Used243* by KeyTool only.244*245* The publicKey is not necessarily to be an instance of246* X509Key in some JCA/JCE providers, for example SunPKCS11.247*/248public PublicKey getPublicKeyAnyway() {249return publicKey;250}251252/**253* Returns the private key of the generated key pair.254*255* <P><STRONG><em>Be extremely careful when handling private keys.256* When private keys are not kept secret, they lose their ability257* to securely authenticate specific entities ... that is a huge258* security risk!</em></STRONG>259*/260public PrivateKey getPrivateKey ()261{262return privateKey;263}264265/**266* Returns a self-signed X.509v3 certificate for the public key.267* The certificate is immediately valid. No extensions.268*269* <P>Such certificates normally are used to identify a "Certificate270* Authority" (CA). Accordingly, they will not always be accepted by271* other parties. However, such certificates are also useful when272* you are bootstrapping your security infrastructure, or deploying273* system prototypes.274*275* @param myname X.500 name of the subject (who is also the issuer)276* @param firstDate the issue time of the certificate277* @param validity how long the certificate should be valid, in seconds278* @exception CertificateException on certificate handling errors.279* @exception InvalidKeyException on key handling errors.280* @exception SignatureException on signature handling errors.281* @exception NoSuchAlgorithmException on unrecognized algorithms.282* @exception NoSuchProviderException on unrecognized providers.283*/284public X509Certificate getSelfCertificate (285X500Name myname, Date firstDate, long validity)286throws CertificateException, InvalidKeyException, SignatureException,287NoSuchAlgorithmException, NoSuchProviderException288{289return getSelfCertificate(myname, firstDate, validity, null);290}291292// Like above, plus a CertificateExtensions argument, which can be null.293// Create a self-signed certificate, or a certificate that is signed by294// a signer when the signer's private key is provided.295public X509Certificate getSelfCertificate (X500Name myname, Date firstDate,296long validity, CertificateExtensions ext)297throws CertificateException, InvalidKeyException, SignatureException,298NoSuchAlgorithmException, NoSuchProviderException299{300X509CertImpl cert;301Date lastDate;302303try {304lastDate = new Date ();305lastDate.setTime (firstDate.getTime () + validity * 1000);306307CertificateValidity interval =308new CertificateValidity(firstDate,lastDate);309310X509CertInfo info = new X509CertInfo();311// Add all mandatory attributes312info.set(X509CertInfo.VERSION,313new CertificateVersion(CertificateVersion.V3));314if (prng == null) {315prng = new SecureRandom();316}317info.set(X509CertInfo.SERIAL_NUMBER,318CertificateSerialNumber.newRandom64bit(prng));319info.set(X509CertInfo.SUBJECT, myname);320info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));321info.set(X509CertInfo.VALIDITY, interval);322if (signerFlag) {323// use signer's subject name to set the issuer name324info.set(X509CertInfo.ISSUER, signerSubjectName);325} else {326info.set(X509CertInfo.ISSUER, myname);327}328if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext);329330cert = new X509CertImpl(info);331if (signerFlag) {332// use signer's private key to sign333cert.sign(signerPrivateKey, sigAlg);334} else {335cert.sign(privateKey, sigAlg);336}337338return cert;339340} catch (IOException e) {341throw new CertificateEncodingException("getSelfCert: " +342e.getMessage());343}344}345346// Keep the old method347public X509Certificate getSelfCertificate (X500Name myname, long validity)348throws CertificateException, InvalidKeyException, SignatureException,349NoSuchAlgorithmException, NoSuchProviderException350{351return getSelfCertificate(myname, new Date(), validity);352}353354private SecureRandom prng;355private String keyType;356private String sigAlg;357private KeyPairGenerator keyGen;358private PublicKey publicKey;359private PrivateKey privateKey;360private boolean signerFlag;361private PrivateKey signerPrivateKey;362private X500Name signerSubjectName;363}364365366