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 /** 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 /** 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 }