|
1 /* |
|
2 * Copyright 1996-2007 Sun Microsystems, Inc. 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. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package sun.security.x509; |
|
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.pkcs.PKCS10; |
|
36 |
|
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". |
|
70 * @exception NoSuchAlgorithmException on unrecognized algorithms. |
|
71 */ |
|
72 public CertAndKeyGen (String keyType, String sigAlg) |
|
73 throws NoSuchAlgorithmException |
|
74 { |
|
75 keyGen = KeyPairGenerator.getInstance(keyType); |
|
76 this.sigAlg = sigAlg; |
|
77 } |
|
78 |
|
79 /** |
|
80 * Creates a CertAndKeyGen object for a particular key type, |
|
81 * signature algorithm, and provider. |
|
82 * |
|
83 * @param keyType type of key, e.g. "RSA", "DSA" |
|
84 * @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA", |
|
85 * "MD2WithRSA", "SHAwithDSA". |
|
86 * @param providerName name of the provider |
|
87 * @exception NoSuchAlgorithmException on unrecognized algorithms. |
|
88 * @exception NoSuchProviderException on unrecognized providers. |
|
89 */ |
|
90 public CertAndKeyGen (String keyType, String sigAlg, String providerName) |
|
91 throws NoSuchAlgorithmException, NoSuchProviderException |
|
92 { |
|
93 if (providerName == null) { |
|
94 keyGen = KeyPairGenerator.getInstance(keyType); |
|
95 } else { |
|
96 try { |
|
97 keyGen = KeyPairGenerator.getInstance(keyType, providerName); |
|
98 } catch (Exception e) { |
|
99 // try first available provider instead |
|
100 keyGen = KeyPairGenerator.getInstance(keyType); |
|
101 } |
|
102 } |
|
103 this.sigAlg = sigAlg; |
|
104 } |
|
105 |
|
106 /** |
|
107 * Sets the source of random numbers used when generating keys. |
|
108 * If you do not provide one, a system default facility is used. |
|
109 * You may wish to provide your own source of random numbers |
|
110 * to get a reproducible sequence of keys and signatures, or |
|
111 * because you may be able to take advantage of strong sources |
|
112 * of randomness/entropy in your environment. |
|
113 */ |
|
114 public void setRandom (SecureRandom generator) |
|
115 { |
|
116 prng = generator; |
|
117 } |
|
118 |
|
119 // want "public void generate (X509Certificate)" ... inherit DSA/D-H param |
|
120 |
|
121 /** |
|
122 * Generates a random public/private key pair, with a given key |
|
123 * size. Different algorithms provide different degrees of security |
|
124 * for the same key size, because of the "work factor" involved in |
|
125 * brute force attacks. As computers become faster, it becomes |
|
126 * easier to perform such attacks. Small keys are to be avoided. |
|
127 * |
|
128 * <P>Note that not all values of "keyBits" are valid for all |
|
129 * algorithms, and not all public key algorithms are currently |
|
130 * supported for use in X.509 certificates. If the algorithm |
|
131 * you specified does not produce X.509 compatible keys, an |
|
132 * invalid key exception is thrown. |
|
133 * |
|
134 * @param keyBits the number of bits in the keys. |
|
135 * @exception InvalidKeyException if the environment does not |
|
136 * provide X.509 public keys for this signature algorithm. |
|
137 */ |
|
138 public void generate (int keyBits) |
|
139 throws InvalidKeyException |
|
140 { |
|
141 KeyPair pair; |
|
142 |
|
143 try { |
|
144 if (prng == null) { |
|
145 prng = new SecureRandom(); |
|
146 } |
|
147 keyGen.initialize(keyBits, prng); |
|
148 pair = keyGen.generateKeyPair(); |
|
149 |
|
150 } catch (Exception e) { |
|
151 throw new IllegalArgumentException(e.getMessage()); |
|
152 } |
|
153 |
|
154 publicKey = pair.getPublic(); |
|
155 privateKey = pair.getPrivate(); |
|
156 } |
|
157 |
|
158 |
|
159 /** |
|
160 * Returns the public key of the generated key pair if it is of type |
|
161 * <code>X509Key</code>, or null if the public key is of a different type. |
|
162 * |
|
163 * XXX Note: This behaviour is needed for backwards compatibility. |
|
164 * What this method really should return is the public key of the |
|
165 * generated key pair, regardless of whether or not it is an instance of |
|
166 * <code>X509Key</code>. Accordingly, the return type of this method |
|
167 * should be <code>PublicKey</code>. |
|
168 */ |
|
169 public X509Key getPublicKey() |
|
170 { |
|
171 if (!(publicKey instanceof X509Key)) { |
|
172 return null; |
|
173 } |
|
174 return (X509Key)publicKey; |
|
175 } |
|
176 |
|
177 |
|
178 /** |
|
179 * Returns the private key of the generated key pair. |
|
180 * |
|
181 * <P><STRONG><em>Be extremely careful when handling private keys. |
|
182 * When private keys are not kept secret, they lose their ability |
|
183 * to securely authenticate specific entities ... that is a huge |
|
184 * security risk!</em></STRONG> |
|
185 */ |
|
186 public PrivateKey getPrivateKey () |
|
187 { |
|
188 return privateKey; |
|
189 } |
|
190 |
|
191 |
|
192 /** |
|
193 * Returns a self-signed X.509v1 certificate for the public key. |
|
194 * The certificate is immediately valid. |
|
195 * |
|
196 * <P>Such certificates normally are used to identify a "Certificate |
|
197 * Authority" (CA). Accordingly, they will not always be accepted by |
|
198 * other parties. However, such certificates are also useful when |
|
199 * you are bootstrapping your security infrastructure, or deploying |
|
200 * system prototypes. |
|
201 * |
|
202 * @deprecated Use the new <a href = |
|
203 * "#getSelfCertificate(sun.security.x509.X500Name, long)"> |
|
204 * |
|
205 * @param myname X.500 name of the subject (who is also the issuer) |
|
206 * @param validity how long the certificate should be valid, in seconds |
|
207 */ |
|
208 @Deprecated |
|
209 public X509Cert getSelfCert (X500Name myname, long validity) |
|
210 throws InvalidKeyException, SignatureException, NoSuchAlgorithmException |
|
211 { |
|
212 X509Certificate cert; |
|
213 |
|
214 try { |
|
215 cert = getSelfCertificate(myname, validity); |
|
216 return new X509Cert(cert.getEncoded()); |
|
217 } catch (CertificateException e) { |
|
218 throw new SignatureException(e.getMessage()); |
|
219 } catch (NoSuchProviderException e) { |
|
220 throw new NoSuchAlgorithmException(e.getMessage()); |
|
221 } catch (IOException e) { |
|
222 throw new SignatureException(e.getMessage()); |
|
223 } |
|
224 } |
|
225 |
|
226 |
|
227 /** |
|
228 * Returns a self-signed X.509v3 certificate for the public key. |
|
229 * The certificate is immediately valid. No extensions. |
|
230 * |
|
231 * <P>Such certificates normally are used to identify a "Certificate |
|
232 * Authority" (CA). Accordingly, they will not always be accepted by |
|
233 * other parties. However, such certificates are also useful when |
|
234 * you are bootstrapping your security infrastructure, or deploying |
|
235 * system prototypes. |
|
236 * |
|
237 * @param myname X.500 name of the subject (who is also the issuer) |
|
238 * @param firstDate the issue time of the certificate |
|
239 * @param validity how long the certificate should be valid, in seconds |
|
240 * @exception CertificateException on certificate handling errors. |
|
241 * @exception InvalidKeyException on key handling errors. |
|
242 * @exception SignatureException on signature handling errors. |
|
243 * @exception NoSuchAlgorithmException on unrecognized algorithms. |
|
244 * @exception NoSuchProviderException on unrecognized providers. |
|
245 */ |
|
246 public X509Certificate getSelfCertificate ( |
|
247 X500Name myname, Date firstDate, long validity) |
|
248 throws CertificateException, InvalidKeyException, SignatureException, |
|
249 NoSuchAlgorithmException, NoSuchProviderException |
|
250 { |
|
251 X500Signer issuer; |
|
252 X509CertImpl cert; |
|
253 Date lastDate; |
|
254 |
|
255 try { |
|
256 issuer = getSigner (myname); |
|
257 |
|
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, |
|
269 new CertificateSerialNumber((int)(firstDate.getTime()/1000))); |
|
270 AlgorithmId algID = issuer.getAlgorithmId(); |
|
271 info.set(X509CertInfo.ALGORITHM_ID, |
|
272 new CertificateAlgorithmId(algID)); |
|
273 info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(myname)); |
|
274 info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey)); |
|
275 info.set(X509CertInfo.VALIDITY, interval); |
|
276 info.set(X509CertInfo.ISSUER, |
|
277 new CertificateIssuerName(issuer.getSigner())); |
|
278 |
|
279 CertificateExtensions ext = new CertificateExtensions(); |
|
280 ext.set(SubjectKeyIdentifierExtension.NAME, |
|
281 new SubjectKeyIdentifierExtension( |
|
282 new KeyIdentifier(publicKey).getIdentifier())); |
|
283 info.set(X509CertInfo.EXTENSIONS, ext); |
|
284 |
|
285 cert = new X509CertImpl(info); |
|
286 cert.sign(privateKey, this.sigAlg); |
|
287 |
|
288 return (X509Certificate)cert; |
|
289 |
|
290 } catch (IOException e) { |
|
291 throw new CertificateEncodingException("getSelfCert: " + |
|
292 e.getMessage()); |
|
293 } |
|
294 } |
|
295 |
|
296 // Keep the old method |
|
297 public X509Certificate getSelfCertificate (X500Name myname, long validity) |
|
298 throws CertificateException, InvalidKeyException, SignatureException, |
|
299 NoSuchAlgorithmException, NoSuchProviderException |
|
300 { |
|
301 return getSelfCertificate(myname, new Date(), validity); |
|
302 } |
|
303 |
|
304 /** |
|
305 * Returns a PKCS #10 certificate request. The caller uses either |
|
306 * <code>PKCS10.print</code> or <code>PKCS10.toByteArray</code> |
|
307 * operations on the result, to get the request in an appropriate |
|
308 * transmission format. |
|
309 * |
|
310 * <P>PKCS #10 certificate requests are sent, along with some proof |
|
311 * of identity, to Certificate Authorities (CAs) which then issue |
|
312 * X.509 public key certificates. |
|
313 * |
|
314 * @param myname X.500 name of the subject |
|
315 * @exception InvalidKeyException on key handling errors. |
|
316 * @exception SignatureException on signature handling errors. |
|
317 */ |
|
318 public PKCS10 getCertRequest (X500Name myname) |
|
319 throws InvalidKeyException, SignatureException |
|
320 { |
|
321 PKCS10 req = new PKCS10 (publicKey); |
|
322 |
|
323 try { |
|
324 req.encodeAndSign (getSigner (myname)); |
|
325 |
|
326 } catch (CertificateException e) { |
|
327 throw new SignatureException (sigAlg + " CertificateException"); |
|
328 |
|
329 } catch (IOException e) { |
|
330 throw new SignatureException (sigAlg + " IOException"); |
|
331 |
|
332 } catch (NoSuchAlgorithmException e) { |
|
333 // "can't happen" |
|
334 throw new SignatureException (sigAlg + " unavailable?"); |
|
335 } |
|
336 return req; |
|
337 } |
|
338 |
|
339 private X500Signer getSigner (X500Name me) |
|
340 throws InvalidKeyException, NoSuchAlgorithmException |
|
341 { |
|
342 Signature signature = Signature.getInstance(sigAlg); |
|
343 |
|
344 // XXX should have a way to pass prng to the signature |
|
345 // algorithm ... appropriate for DSS/DSA, not RSA |
|
346 |
|
347 signature.initSign (privateKey); |
|
348 return new X500Signer (signature, me); |
|
349 } |
|
350 |
|
351 private SecureRandom prng; |
|
352 private String sigAlg; |
|
353 private KeyPairGenerator keyGen; |
|
354 private PublicKey publicKey; |
|
355 private PrivateKey privateKey; |
|
356 } |