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