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
26package sun.security.tools.keytool;
27
28import java.io.IOException;
29import java.security.cert.X509Certificate;
30import java.security.cert.CertificateException;
31import java.security.cert.CertificateEncodingException;
32import java.security.*;
33import java.util.Date;
34
35import sun.security.pkcs10.PKCS10;
36import sun.security.x509.*;
37
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 */
63public 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    /**
127     * Generates a random public/private key pair, with a given key
128     * size.  Different algorithms provide different degrees of security
129     * for the same key size, because of the "work factor" involved in
130     * brute force attacks.  As computers become faster, it becomes
131     * easier to perform such attacks.  Small keys are to be avoided.
132     *
133     * <P>Note that not all values of "keyBits" are valid for all
134     * algorithms, and not all public key algorithms are currently
135     * supported for use in X.509 certificates.  If the algorithm
136     * you specified does not produce X.509 compatible keys, an
137     * invalid key exception is thrown.
138     *
139     * @param keyBits the number of bits in the keys.
140     * @exception InvalidKeyException if the environment does not
141     *  provide X.509 public keys for this signature algorithm.
142     */
143    public void generate (int keyBits)
144    throws InvalidKeyException
145    {
146        KeyPair pair;
147
148        try {
149            if (prng == null) {
150                prng = new SecureRandom();
151            }
152            keyGen.initialize(keyBits, prng);
153            pair = keyGen.generateKeyPair();
154
155        } catch (Exception e) {
156            throw new IllegalArgumentException(e.getMessage());
157        }
158
159        publicKey = pair.getPublic();
160        privateKey = pair.getPrivate();
161
162        // publicKey's format must be X.509 otherwise
163        // the whole CertGen part of this class is broken.
164        if (!"X.509".equalsIgnoreCase(publicKey.getFormat())) {
165            throw new IllegalArgumentException("Public key format is "
166                + publicKey.getFormat() + ", must be X.509");
167        }
168
169        if (sigAlg == null) {
170            sigAlg = AlgorithmId.getDefaultSigAlgForKey(privateKey);
171            if (sigAlg == null) {
172                throw new IllegalArgumentException(
173                        "Cannot derive signature algorithm from "
174                                + privateKey.getAlgorithm());
175            }
176        }
177    }
178
179    /**
180     * Returns the public key of the generated key pair if it is of type
181     * <code>X509Key</code>, or null if the public key is of a different type.
182     *
183     * XXX Note: This behaviour is needed for backwards compatibility.
184     * What this method really should return is the public key of the
185     * generated key pair, regardless of whether or not it is an instance of
186     * <code>X509Key</code>. Accordingly, the return type of this method
187     * should be <code>PublicKey</code>.
188     */
189    public X509Key getPublicKey()
190    {
191        if (!(publicKey instanceof X509Key)) {
192            return null;
193        }
194        return (X509Key)publicKey;
195    }
196
197    /**
198     * Always returns the public key of the generated key pair. Used
199     * by KeyTool only.
200     *
201     * The publicKey is not necessarily to be an instance of
202     * X509Key in some JCA/JCE providers, for example SunPKCS11.
203     */
204    public PublicKey getPublicKeyAnyway() {
205        return publicKey;
206    }
207
208    /**
209     * Returns the private key of the generated key pair.
210     *
211     * <P><STRONG><em>Be extremely careful when handling private keys.
212     * When private keys are not kept secret, they lose their ability
213     * to securely authenticate specific entities ... that is a huge
214     * security risk!</em></STRONG>
215     */
216    public PrivateKey getPrivateKey ()
217    {
218        return privateKey;
219    }
220
221    /**
222     * Returns a self-signed X.509v3 certificate for the public key.
223     * The certificate is immediately valid. No extensions.
224     *
225     * <P>Such certificates normally are used to identify a "Certificate
226     * Authority" (CA).  Accordingly, they will not always be accepted by
227     * other parties.  However, such certificates are also useful when
228     * you are bootstrapping your security infrastructure, or deploying
229     * system prototypes.
230     *
231     * @param myname X.500 name of the subject (who is also the issuer)
232     * @param firstDate the issue time of the certificate
233     * @param validity how long the certificate should be valid, in seconds
234     * @exception CertificateException on certificate handling errors.
235     * @exception InvalidKeyException on key handling errors.
236     * @exception SignatureException on signature handling errors.
237     * @exception NoSuchAlgorithmException on unrecognized algorithms.
238     * @exception NoSuchProviderException on unrecognized providers.
239     */
240    public X509Certificate getSelfCertificate (
241            X500Name myname, Date firstDate, long validity)
242    throws CertificateException, InvalidKeyException, SignatureException,
243        NoSuchAlgorithmException, NoSuchProviderException
244    {
245        return getSelfCertificate(myname, firstDate, validity, null);
246    }
247
248    // Like above, plus a CertificateExtensions argument, which can be null.
249    public X509Certificate getSelfCertificate (X500Name myname, Date firstDate,
250            long validity, CertificateExtensions ext)
251    throws CertificateException, InvalidKeyException, SignatureException,
252        NoSuchAlgorithmException, NoSuchProviderException
253    {
254        X509CertImpl    cert;
255        Date            lastDate;
256
257        try {
258            lastDate = new Date ();
259            lastDate.setTime (firstDate.getTime () + validity * 1000);
260
261            CertificateValidity interval =
262                                   new CertificateValidity(firstDate,lastDate);
263
264            X509CertInfo info = new X509CertInfo();
265            // Add all mandatory attributes
266            info.set(X509CertInfo.VERSION,
267                     new CertificateVersion(CertificateVersion.V3));
268            info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(
269                    new java.util.Random().nextInt() & 0x7fffffff));
270            AlgorithmId algID = AlgorithmId.get(sigAlg);
271            info.set(X509CertInfo.ALGORITHM_ID,
272                     new CertificateAlgorithmId(algID));
273            info.set(X509CertInfo.SUBJECT, myname);
274            info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
275            info.set(X509CertInfo.VALIDITY, interval);
276            info.set(X509CertInfo.ISSUER, myname);
277            if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext);
278
279            cert = new X509CertImpl(info);
280            cert.sign(privateKey, this.sigAlg);
281
282            return (X509Certificate)cert;
283
284        } catch (IOException e) {
285             throw new CertificateEncodingException("getSelfCert: " +
286                                                    e.getMessage());
287        }
288    }
289
290    // Keep the old method
291    public X509Certificate getSelfCertificate (X500Name myname, long validity)
292    throws CertificateException, InvalidKeyException, SignatureException,
293        NoSuchAlgorithmException, NoSuchProviderException
294    {
295        return getSelfCertificate(myname, new Date(), validity);
296    }
297
298    /**
299     * Returns a PKCS #10 certificate request.  The caller uses either
300     * <code>PKCS10.print</code> or <code>PKCS10.toByteArray</code>
301     * operations on the result, to get the request in an appropriate
302     * transmission format.
303     *
304     * <P>PKCS #10 certificate requests are sent, along with some proof
305     * of identity, to Certificate Authorities (CAs) which then issue
306     * X.509 public key certificates.
307     *
308     * @param myname X.500 name of the subject
309     * @exception InvalidKeyException on key handling errors.
310     * @exception SignatureException on signature handling errors.
311     */
312    public PKCS10 getCertRequest (X500Name myname)
313    throws InvalidKeyException, SignatureException
314    {
315        PKCS10  req = new PKCS10 (publicKey);
316
317        try {
318            Signature signature = Signature.getInstance(sigAlg);
319            signature.initSign (privateKey);
320            req.encodeAndSign(myname, signature);
321
322        } catch (CertificateException e) {
323            throw new SignatureException (sigAlg + " CertificateException");
324
325        } catch (IOException e) {
326            throw new SignatureException (sigAlg + " IOException");
327
328        } catch (NoSuchAlgorithmException e) {
329            // "can't happen"
330            throw new SignatureException (sigAlg + " unavailable?");
331        }
332        return req;
333    }
334
335    private SecureRandom        prng;
336    private String              sigAlg;
337    private KeyPairGenerator    keyGen;
338    private PublicKey           publicKey;
339    private PrivateKey          privateKey;
340}
341