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 }