diff -r f723098d438c -r 3041082abb40 jdk/src/share/classes/sun/security/tools/keytool/CertAndKeyGen.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/security/tools/keytool/CertAndKeyGen.java Sun Oct 14 22:58:59 2012 +0100 @@ -0,0 +1,328 @@ +/* + * Copyright (c) 1996, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.tools.keytool; + +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateEncodingException; +import java.security.*; +import java.util.Date; + +import sun.security.pkcs10.PKCS10; +import sun.security.x509.*; + + +/** + * Generate a pair of keys, and provide access to them. This class is + * provided primarily for ease of use. + * + *

This provides some simple certificate management functionality. + * Specifically, it allows you to create self-signed X.509 certificates + * as well as PKCS 10 based certificate signing requests. + * + *

Keys for some public key signature algorithms have algorithm + * parameters, such as DSS/DSA. Some sites' Certificate Authorities + * adopt fixed algorithm parameters, which speeds up some operations + * including key generation and signing. 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. + * + *

Also, note that at this time only signature-capable keys may be + * acquired through this interface. Diffie-Hellman keys, used for secure + * key exchange, may be supported later. + * + * @author David Brownell + * @author Hemma Prafullchandra + * @see PKCS10 + * @see X509CertImpl + */ +public final class CertAndKeyGen { + /** + * Creates a CertAndKeyGen object for a particular key type + * and signature algorithm. + * + * @param keyType type of key, e.g. "RSA", "DSA" + * @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA", + * "MD2WithRSA", "SHAwithDSA". + * @exception NoSuchAlgorithmException on unrecognized algorithms. + */ + public CertAndKeyGen (String keyType, String sigAlg) + throws NoSuchAlgorithmException + { + keyGen = KeyPairGenerator.getInstance(keyType); + this.sigAlg = sigAlg; + } + + /** + * Creates a CertAndKeyGen object for a particular key type, + * signature algorithm, and provider. + * + * @param keyType type of key, e.g. "RSA", "DSA" + * @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA", + * "MD2WithRSA", "SHAwithDSA". + * @param providerName name of the provider + * @exception NoSuchAlgorithmException on unrecognized algorithms. + * @exception NoSuchProviderException on unrecognized providers. + */ + public CertAndKeyGen (String keyType, String sigAlg, String providerName) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (providerName == null) { + keyGen = KeyPairGenerator.getInstance(keyType); + } else { + try { + keyGen = KeyPairGenerator.getInstance(keyType, providerName); + } catch (Exception e) { + // try first available provider instead + keyGen = KeyPairGenerator.getInstance(keyType); + } + } + this.sigAlg = sigAlg; + } + + /** + * Sets the source of random numbers used when generating keys. + * If you do not provide one, a system default facility is used. + * You may wish to provide your own source of random numbers + * to get a reproducible sequence of keys and signatures, or + * because you may be able to take advantage of strong sources + * of randomness/entropy in your environment. + */ + public void setRandom (SecureRandom generator) + { + 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. + * + *

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; + + try { + if (prng == null) { + prng = new SecureRandom(); + } + keyGen.initialize(keyBits, prng); + pair = keyGen.generateKeyPair(); + + } catch (Exception e) { + throw new IllegalArgumentException(e.getMessage()); + } + + publicKey = pair.getPublic(); + privateKey = pair.getPrivate(); + + // publicKey's format must be X.509 otherwise + // the whole CertGen part of this class is broken. + if (!"X.509".equalsIgnoreCase(publicKey.getFormat())) { + throw new IllegalArgumentException("publicKey's is not X.509, but " + + publicKey.getFormat()); + } + } + + + /** + * Returns the public key of the generated key pair if it is of type + * X509Key, or null if the public key is of a different type. + * + * XXX Note: This behaviour is needed for backwards compatibility. + * What this method really should return is the public key of the + * generated key pair, regardless of whether or not it is an instance of + * X509Key. Accordingly, the return type of this method + * should be PublicKey. + */ + public X509Key getPublicKey() + { + if (!(publicKey instanceof X509Key)) { + return null; + } + return (X509Key)publicKey; + } + + /** + * Always returns the public key of the generated key pair. Used + * by KeyTool only. + * + * The publicKey is not necessarily to be an instance of + * X509Key in some JCA/JCE providers, for example SunPKCS11. + */ + public PublicKey getPublicKeyAnyway() { + return publicKey; + } + + /** + * Returns the private key of the generated key pair. + * + *

Be extremely careful when handling private keys. + * When private keys are not kept secret, they lose their ability + * to securely authenticate specific entities ... that is a huge + * security risk! + */ + public PrivateKey getPrivateKey () + { + return privateKey; + } + + /** + * Returns a self-signed X.509v3 certificate for the public key. + * The certificate is immediately valid. No extensions. + * + *

Such certificates normally are used to identify a "Certificate + * Authority" (CA). Accordingly, they will not always be accepted by + * other parties. However, such certificates are also useful when + * you are bootstrapping your security infrastructure, or deploying + * system prototypes. + * + * @param myname X.500 name of the subject (who is also the issuer) + * @param firstDate the issue time of the certificate + * @param validity how long the certificate should be valid, in seconds + * @exception CertificateException on certificate handling errors. + * @exception InvalidKeyException on key handling errors. + * @exception SignatureException on signature handling errors. + * @exception NoSuchAlgorithmException on unrecognized algorithms. + * @exception NoSuchProviderException on unrecognized providers. + */ + public X509Certificate getSelfCertificate ( + X500Name myname, Date firstDate, long validity) + throws CertificateException, InvalidKeyException, SignatureException, + NoSuchAlgorithmException, NoSuchProviderException + { + return getSelfCertificate(myname, firstDate, validity, null); + } + + // Like above, plus a CertificateExtensions argument, which can be null. + public X509Certificate getSelfCertificate (X500Name myname, Date firstDate, + long validity, CertificateExtensions ext) + throws CertificateException, InvalidKeyException, SignatureException, + NoSuchAlgorithmException, NoSuchProviderException + { + X509CertImpl cert; + Date lastDate; + + try { + lastDate = new Date (); + lastDate.setTime (firstDate.getTime () + validity * 1000); + + CertificateValidity interval = + new CertificateValidity(firstDate,lastDate); + + X509CertInfo info = new X509CertInfo(); + // Add all mandatory attributes + info.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( + new java.util.Random().nextInt() & 0x7fffffff)); + AlgorithmId algID = AlgorithmId.get(sigAlg); + info.set(X509CertInfo.ALGORITHM_ID, + new CertificateAlgorithmId(algID)); + info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(myname)); + info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey)); + info.set(X509CertInfo.VALIDITY, interval); + info.set(X509CertInfo.ISSUER, new CertificateIssuerName(myname)); + if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext); + + cert = new X509CertImpl(info); + cert.sign(privateKey, this.sigAlg); + + return (X509Certificate)cert; + + } catch (IOException e) { + throw new CertificateEncodingException("getSelfCert: " + + e.getMessage()); + } + } + + // Keep the old method + public X509Certificate getSelfCertificate (X500Name myname, long validity) + throws CertificateException, InvalidKeyException, SignatureException, + NoSuchAlgorithmException, NoSuchProviderException + { + return getSelfCertificate(myname, new Date(), validity); + } + + /** + * Returns a PKCS #10 certificate request. The caller uses either + * PKCS10.print or PKCS10.toByteArray + * operations on the result, to get the request in an appropriate + * transmission format. + * + *

PKCS #10 certificate requests are sent, along with some proof + * of identity, to Certificate Authorities (CAs) which then issue + * X.509 public key certificates. + * + * @param myname X.500 name of the subject + * @exception InvalidKeyException on key handling errors. + * @exception SignatureException on signature handling errors. + */ + public PKCS10 getCertRequest (X500Name myname) + throws InvalidKeyException, SignatureException + { + PKCS10 req = new PKCS10 (publicKey); + + try { + Signature signature = Signature.getInstance(sigAlg); + signature.initSign (privateKey); + req.encodeAndSign(myname, signature); + + } catch (CertificateException e) { + throw new SignatureException (sigAlg + " CertificateException"); + + } catch (IOException e) { + throw new SignatureException (sigAlg + " IOException"); + + } catch (NoSuchAlgorithmException e) { + // "can't happen" + throw new SignatureException (sigAlg + " unavailable?"); + } + return req; + } + + private SecureRandom prng; + private String sigAlg; + private KeyPairGenerator keyGen; + private PublicKey publicKey; + private PrivateKey privateKey; +}