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