1 /*
   2  * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.tools.keytool;
  27 
  28 import java.io.IOException;
  29 import java.security.cert.X509Certificate;
  30 import java.security.cert.CertificateException;
  31 import java.security.cert.CertificateEncodingException;
  32 import java.security.*;
  33 import java.security.spec.AlgorithmParameterSpec;
  34 import java.util.Date;
  35 
  36 import sun.security.pkcs10.PKCS10;
  37 import sun.security.x509.*;
  38 
  39 /**
  40  * Generate a pair of keys, and provide access to them.  This class is
  41  * provided primarily for ease of use.
  42  *
  43  * <P>This provides some simple certificate management functionality.
  44  * Specifically, it allows you to create self-signed X.509 certificates
  45  * as well as PKCS 10 based certificate signing requests.
  46  *
  47  * <P>Keys for some public key signature algorithms have algorithm
  48  * parameters, such as DSS/DSA.  Some sites' Certificate Authorities
  49  * adopt fixed algorithm parameters, which speeds up some operations
  50  * including key generation and signing.  <em>At this time, this interface
  51  * does not provide a way to provide such algorithm parameters, e.g.
  52  * by providing the CA certificate which includes those parameters.</em>
  53  *
  54  * <P>Also, note that at this time only signature-capable keys may be
  55  * acquired through this interface.  Diffie-Hellman keys, used for secure
  56  * key exchange, may be supported later.
  57  *
  58  * @author David Brownell
  59  * @author Hemma Prafullchandra
  60  * @see PKCS10
  61  * @see X509CertImpl
  62  */
  63 public final class CertAndKeyGen {
  64     /**
  65      * Creates a CertAndKeyGen object for a particular key type
  66      * 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 default
  71      *          algorithm matching the private key will be chosen after
  72      *          the first keypair is generated.
  73      * @exception NoSuchAlgorithmException on unrecognized algorithms.
  74      */
  75     public CertAndKeyGen (String keyType, String sigAlg)
  76     throws NoSuchAlgorithmException
  77     {
  78         keyGen = KeyPairGenerator.getInstance(keyType);
  79         this.sigAlg = sigAlg;
  80     }
  81 
  82     /**
  83      * Creates a CertAndKeyGen object for a particular key type,
  84      * signature algorithm, and provider.
  85      *
  86      * @param keyType type of key, e.g. "RSA", "DSA"
  87      * @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA",
  88      *          "MD2WithRSA", "SHAwithDSA". If set to null, a default
  89      *          algorithm matching the private key will be chosen after
  90      *          the first keypair is generated.
  91      * @param providerName name of the provider
  92      * @exception NoSuchAlgorithmException on unrecognized algorithms.
  93      * @exception NoSuchProviderException on unrecognized providers.
  94      */
  95     public CertAndKeyGen (String keyType, String sigAlg, String providerName)
  96     throws NoSuchAlgorithmException, NoSuchProviderException
  97     {
  98         if (providerName == null) {
  99             keyGen = KeyPairGenerator.getInstance(keyType);
 100         } else {
 101             try {
 102                 keyGen = KeyPairGenerator.getInstance(keyType, providerName);
 103             } catch (Exception e) {
 104                 // try first available provider instead
 105                 keyGen = KeyPairGenerator.getInstance(keyType);
 106             }
 107         }
 108         this.sigAlg = sigAlg;
 109     }
 110 
 111     /**
 112      * Sets the source of random numbers used when generating keys.
 113      * If you do not provide one, a system default facility is used.
 114      * You may wish to provide your own source of random numbers
 115      * to get a reproducible sequence of keys and signatures, or
 116      * because you may be able to take advantage of strong sources
 117      * of randomness/entropy in your environment.
 118      */
 119     public void         setRandom (SecureRandom generator)
 120     {
 121         prng = generator;
 122     }
 123 
 124     // want "public void generate (X509Certificate)" ... inherit DSA/D-H param
 125 
 126     public void generate(int keyBits) {
 127         if (keyBits != -1) {
 128             try {
 129                 if (prng == null) {
 130                     prng = new SecureRandom();
 131                 }
 132                 keyGen.initialize(keyBits, prng);
 133 
 134             } catch (Exception e) {
 135                 throw new IllegalArgumentException(e.getMessage());
 136             }
 137         }
 138         generateInternal();
 139     }
 140 
 141     /**
 142      * Generates a random public/private key pair, with a given key
 143      * size.  Different algorithms provide different degrees of security
 144      * for the same key size, because of the "work factor" involved in
 145      * brute force attacks.  As computers become faster, it becomes
 146      * easier to perform such attacks.  Small keys are to be avoided.
 147      *
 148      * <P>Note that not all values of "keyBits" are valid for all
 149      * algorithms, and not all public key algorithms are currently
 150      * supported for use in X.509 certificates.  If the algorithm
 151      * you specified does not produce X.509 compatible keys, an
 152      * invalid key exception is thrown.
 153      *
 154      * @param keyBits the number of bits in the keys.
 155      * @exception InvalidKeyException if the environment does not
 156      *  provide X.509 public keys for this signature algorithm.
 157      */
 158     public void generateInternal() {
 159         KeyPair pair = keyGen.generateKeyPair();
 160 
 161         publicKey = pair.getPublic();
 162         privateKey = pair.getPrivate();
 163 
 164         // publicKey's format must be X.509 otherwise
 165         // the whole CertGen part of this class is broken.
 166         if (!"X.509".equalsIgnoreCase(publicKey.getFormat())) {
 167             throw new IllegalArgumentException("Public key format is "
 168                 + publicKey.getFormat() + ", must be X.509");
 169         }
 170 
 171         if (sigAlg == null) {
 172             sigAlg = AlgorithmId.getDefaultSigAlgForKey(privateKey);
 173             if (sigAlg == null) {
 174                 throw new IllegalArgumentException(
 175                         "Cannot derive signature algorithm from "
 176                                 + privateKey.getAlgorithm());
 177             }
 178         }
 179     }
 180 
 181     /**
 182      * Returns the public key of the generated key pair if it is of type
 183      * <code>X509Key</code>, or null if the public key is of a different type.
 184      *
 185      * XXX Note: This behaviour is needed for backwards compatibility.
 186      * What this method really should return is the public key of the
 187      * generated key pair, regardless of whether or not it is an instance of
 188      * <code>X509Key</code>. Accordingly, the return type of this method
 189      * should be <code>PublicKey</code>.
 190      */
 191     public X509Key getPublicKey()
 192     {
 193         if (!(publicKey instanceof X509Key)) {
 194             return null;
 195         }
 196         return (X509Key)publicKey;
 197     }
 198 
 199     /**
 200      * Always returns the public key of the generated key pair. Used
 201      * by KeyTool only.
 202      *
 203      * The publicKey is not necessarily to be an instance of
 204      * X509Key in some JCA/JCE providers, for example SunPKCS11.
 205      */
 206     public PublicKey getPublicKeyAnyway() {
 207         return publicKey;
 208     }
 209 
 210     /**
 211      * Returns the private key of the generated key pair.
 212      *
 213      * <P><STRONG><em>Be extremely careful when handling private keys.
 214      * When private keys are not kept secret, they lose their ability
 215      * to securely authenticate specific entities ... that is a huge
 216      * security risk!</em></STRONG>
 217      */
 218     public PrivateKey getPrivateKey ()
 219     {
 220         return privateKey;
 221     }
 222 
 223     /**
 224      * Returns a self-signed X.509v3 certificate for the public key.
 225      * The certificate is immediately valid. No extensions.
 226      *
 227      * <P>Such certificates normally are used to identify a "Certificate
 228      * Authority" (CA).  Accordingly, they will not always be accepted by
 229      * other parties.  However, such certificates are also useful when
 230      * you are bootstrapping your security infrastructure, or deploying
 231      * system prototypes.
 232      *
 233      * @param myname X.500 name of the subject (who is also the issuer)
 234      * @param firstDate the issue time of the certificate
 235      * @param validity how long the certificate should be valid, in seconds
 236      * @exception CertificateException on certificate handling errors.
 237      * @exception InvalidKeyException on key handling errors.
 238      * @exception SignatureException on signature handling errors.
 239      * @exception NoSuchAlgorithmException on unrecognized algorithms.
 240      * @exception NoSuchProviderException on unrecognized providers.
 241      */
 242     public X509Certificate getSelfCertificate (
 243             X500Name myname, Date firstDate, long validity)
 244     throws CertificateException, InvalidKeyException, SignatureException,
 245         NoSuchAlgorithmException, NoSuchProviderException
 246     {
 247         return getSelfCertificate(myname, firstDate, validity, null);
 248     }
 249 
 250     // Like above, plus a CertificateExtensions argument, which can be null.
 251     public X509Certificate getSelfCertificate (X500Name myname, Date firstDate,
 252             long validity, CertificateExtensions ext)
 253     throws CertificateException, InvalidKeyException, SignatureException,
 254         NoSuchAlgorithmException, NoSuchProviderException
 255     {
 256         X509CertImpl    cert;
 257         Date            lastDate;
 258 
 259         try {
 260             lastDate = new Date ();
 261             lastDate.setTime (firstDate.getTime () + validity * 1000);
 262 
 263             CertificateValidity interval =
 264                                    new CertificateValidity(firstDate,lastDate);
 265 
 266             X509CertInfo info = new X509CertInfo();
 267             AlgorithmParameterSpec params = AlgorithmId
 268                     .getDefaultAlgorithmParameterSpec(sigAlg, privateKey);
 269             // Add all mandatory attributes
 270             info.set(X509CertInfo.VERSION,
 271                      new CertificateVersion(CertificateVersion.V3));
 272             info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(
 273                     new java.util.Random().nextInt() & 0x7fffffff));
 274             AlgorithmId algID = AlgorithmId.getWithParameterSpec(sigAlg, params);
 275             info.set(X509CertInfo.ALGORITHM_ID,
 276                      new CertificateAlgorithmId(algID));
 277             info.set(X509CertInfo.SUBJECT, myname);
 278             info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
 279             info.set(X509CertInfo.VALIDITY, interval);
 280             info.set(X509CertInfo.ISSUER, myname);
 281             if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext);
 282 
 283             cert = new X509CertImpl(info);
 284             cert.sign(privateKey,
 285                     params,
 286                     sigAlg,
 287                     null);
 288 
 289             return (X509Certificate)cert;
 290 
 291         } catch (IOException e) {
 292              throw new CertificateEncodingException("getSelfCert: " +
 293                                                     e.getMessage());
 294         } catch (InvalidAlgorithmParameterException e2) {
 295             throw new SignatureException(
 296                     "Unsupported PSSParameterSpec: " + e2.getMessage());
 297         }
 298     }
 299 
 300     // Keep the old method
 301     public X509Certificate getSelfCertificate (X500Name myname, long validity)
 302     throws CertificateException, InvalidKeyException, SignatureException,
 303         NoSuchAlgorithmException, NoSuchProviderException
 304     {
 305         return getSelfCertificate(myname, new Date(), validity);
 306     }
 307 
 308     /**
 309      * Returns a PKCS #10 certificate request.  The caller uses either
 310      * <code>PKCS10.print</code> or <code>PKCS10.toByteArray</code>
 311      * operations on the result, to get the request in an appropriate
 312      * transmission format.
 313      *
 314      * <P>PKCS #10 certificate requests are sent, along with some proof
 315      * of identity, to Certificate Authorities (CAs) which then issue
 316      * X.509 public key certificates.
 317      *
 318      * @param myname X.500 name of the subject
 319      * @exception InvalidKeyException on key handling errors.
 320      * @exception SignatureException on signature handling errors.
 321      */
 322     // This method is not used inside JDK. Will not update it.
 323     public PKCS10 getCertRequest (X500Name myname)
 324     throws InvalidKeyException, SignatureException
 325     {
 326         PKCS10  req = new PKCS10 (publicKey);
 327 
 328         try {
 329             Signature signature = Signature.getInstance(sigAlg);
 330             signature.initSign (privateKey);
 331             req.encodeAndSign(myname, signature);
 332 
 333         } catch (CertificateException e) {
 334             throw new SignatureException (sigAlg + " CertificateException");
 335 
 336         } catch (IOException e) {
 337             throw new SignatureException (sigAlg + " IOException");
 338 
 339         } catch (NoSuchAlgorithmException e) {
 340             // "can't happen"
 341             throw new SignatureException (sigAlg + " unavailable?");
 342         }
 343         return req;
 344     }
 345 
 346     private SecureRandom        prng;
 347     private String              sigAlg;
 348     private KeyPairGenerator    keyGen;
 349     private PublicKey           publicKey;
 350     private PrivateKey          privateKey;
 351 }