Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java
67847 views
1
/*
2
* Copyright (c) 1996, 2021, 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.ECGenParameterSpec;
34
import java.security.spec.NamedParameterSpec;
35
import java.util.Calendar;
36
import java.util.Date;
37
import java.util.GregorianCalendar;
38
import java.util.TimeZone;
39
40
import sun.security.pkcs10.PKCS10;
41
import sun.security.util.SignatureUtil;
42
import sun.security.x509.*;
43
44
/**
45
* Generate a pair of keys, and provide access to them. This class is
46
* provided primarily for ease of use.
47
*
48
* <P>This provides some simple certificate management functionality.
49
* Specifically, it allows you to create self-signed X.509 certificates
50
* as well as PKCS 10 based certificate signing requests.
51
*
52
* <P>Keys for some public key signature algorithms have algorithm
53
* parameters, such as DSS/DSA. Some sites' Certificate Authorities
54
* adopt fixed algorithm parameters, which speeds up some operations
55
* including key generation and signing. <em>At this time, this interface
56
* supports initializing with a named group.</em>
57
*
58
* <P>Also, note that at this time only signature-capable keys may be
59
* acquired through this interface. Diffie-Hellman keys, used for secure
60
* key exchange, may be supported later.
61
*
62
* @author David Brownell
63
* @author Hemma Prafullchandra
64
* @see PKCS10
65
* @see X509CertImpl
66
*/
67
public final class CertAndKeyGen {
68
/**
69
* Creates a CertAndKeyGen object for a particular key type
70
* and signature algorithm.
71
*
72
* @param keyType type of key, e.g. "RSA", "DSA"
73
* @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA",
74
* "MD2WithRSA", "SHAwithDSA". If set to null, a default
75
* algorithm matching the private key will be chosen after
76
* the first keypair is generated.
77
* @exception NoSuchAlgorithmException on unrecognized algorithms.
78
*/
79
public CertAndKeyGen (String keyType, String sigAlg)
80
throws NoSuchAlgorithmException
81
{
82
keyGen = KeyPairGenerator.getInstance(keyType);
83
this.sigAlg = sigAlg;
84
this.keyType = keyType;
85
}
86
87
/**
88
* @see #CertAndKeyGen(String, String, String, PrivateKey, X500Name)
89
*/
90
public CertAndKeyGen (String keyType, String sigAlg, String providerName)
91
throws NoSuchAlgorithmException, NoSuchProviderException
92
{
93
this(keyType, sigAlg, providerName, null, null);
94
}
95
96
/**
97
* Creates a CertAndKeyGen object for a particular key type,
98
* signature algorithm, and provider. The newly generated cert will
99
* be signed by the signer's private key when it is provided.
100
*
101
* @param keyType type of key, e.g. "RSA", "DSA", "X25519", "DH", etc.
102
* @param sigAlg name of the signature algorithm, e.g. "SHA384WithRSA",
103
* "SHA256withDSA", etc. If set to null, a default
104
* algorithm matching the private key or signer's private
105
* key will be chosen after the first keypair is generated.
106
* @param providerName name of the provider
107
* @param signerPrivateKey (optional) signer's private key
108
* @param signerSubjectName (optional) signer's subject name
109
* @exception NoSuchAlgorithmException on unrecognized algorithms.
110
* @exception NoSuchProviderException on unrecognized providers.
111
*/
112
public CertAndKeyGen(String keyType, String sigAlg, String providerName,
113
PrivateKey signerPrivateKey, X500Name signerSubjectName)
114
throws NoSuchAlgorithmException, NoSuchProviderException
115
{
116
if (providerName == null) {
117
keyGen = KeyPairGenerator.getInstance(keyType);
118
} else {
119
try {
120
keyGen = KeyPairGenerator.getInstance(keyType, providerName);
121
} catch (Exception e) {
122
// try first available provider instead
123
keyGen = KeyPairGenerator.getInstance(keyType);
124
}
125
}
126
this.sigAlg = sigAlg;
127
this.keyType = keyType;
128
this.signerPrivateKey = signerPrivateKey;
129
this.signerSubjectName = signerSubjectName;
130
this.signerFlag = signerPrivateKey != null;
131
}
132
133
/**
134
* Sets the source of random numbers used when generating keys.
135
* If you do not provide one, a system default facility is used.
136
* You may wish to provide your own source of random numbers
137
* to get a reproducible sequence of keys and signatures, or
138
* because you may be able to take advantage of strong sources
139
* of randomness/entropy in your environment.
140
*/
141
public void setRandom (SecureRandom generator)
142
{
143
prng = generator;
144
}
145
146
public void generate(String name) {
147
try {
148
if (prng == null) {
149
prng = new SecureRandom();
150
}
151
try {
152
keyGen.initialize(new NamedParameterSpec(name), prng);
153
} catch (InvalidAlgorithmParameterException e) {
154
if (keyType.equalsIgnoreCase("EC")) {
155
// EC has another NamedParameterSpec
156
keyGen.initialize(new ECGenParameterSpec(name), prng);
157
} else {
158
throw e;
159
}
160
}
161
162
} catch (Exception e) {
163
throw new IllegalArgumentException(e.getMessage());
164
}
165
generateInternal();
166
}
167
168
// want "public void generate (X509Certificate)" ... inherit DSA/D-H param
169
170
public void generate(int keyBits) {
171
if (keyBits != -1) {
172
try {
173
if (prng == null) {
174
prng = new SecureRandom();
175
}
176
keyGen.initialize(keyBits, prng);
177
178
} catch (Exception e) {
179
throw new IllegalArgumentException(e.getMessage());
180
}
181
}
182
generateInternal();
183
}
184
185
/**
186
* Generates a random public/private key pair.
187
*
188
* <P>Note that not all public key algorithms are currently
189
* supported for use in X.509 certificates. If the algorithm
190
* you specified does not produce X.509 compatible keys, an
191
* invalid key exception is thrown.
192
*
193
* @exception IllegalArgumentException if the environment does not
194
* provide X.509 public keys for this signature algorithm.
195
*/
196
private void generateInternal() {
197
KeyPair pair = keyGen.generateKeyPair();
198
publicKey = pair.getPublic();
199
privateKey = pair.getPrivate();
200
201
// publicKey's format must be X.509 otherwise
202
// the whole CertGen part of this class is broken.
203
if (!"X.509".equalsIgnoreCase(publicKey.getFormat())) {
204
throw new IllegalArgumentException("Public key format is "
205
+ publicKey.getFormat() + ", must be X.509");
206
}
207
208
if (sigAlg == null) {
209
if (signerFlag) {
210
sigAlg = SignatureUtil.getDefaultSigAlgForKey(signerPrivateKey);
211
if (sigAlg == null) {
212
throw new IllegalArgumentException(
213
"Cannot derive signature algorithm from "
214
+ signerPrivateKey.getAlgorithm());
215
}
216
} else {
217
sigAlg = SignatureUtil.getDefaultSigAlgForKey(privateKey);
218
if (sigAlg == null) {
219
throw new IllegalArgumentException(
220
"Cannot derive signature algorithm from "
221
+ privateKey.getAlgorithm());
222
}
223
}
224
}
225
}
226
227
/**
228
* Returns the public key of the generated key pair if it is of type
229
* <code>X509Key</code>, or null if the public key is of a different type.
230
*
231
* XXX Note: This behaviour is needed for backwards compatibility.
232
* What this method really should return is the public key of the
233
* generated key pair, regardless of whether or not it is an instance of
234
* <code>X509Key</code>. Accordingly, the return type of this method
235
* should be <code>PublicKey</code>.
236
*/
237
public X509Key getPublicKey()
238
{
239
if (!(publicKey instanceof X509Key)) {
240
return null;
241
}
242
return (X509Key)publicKey;
243
}
244
245
/**
246
* Always returns the public key of the generated key pair. Used
247
* by KeyTool only.
248
*
249
* The publicKey is not necessarily to be an instance of
250
* X509Key in some JCA/JCE providers, for example SunPKCS11.
251
*/
252
public PublicKey getPublicKeyAnyway() {
253
return publicKey;
254
}
255
256
/**
257
* Returns the private key of the generated key pair.
258
*
259
* <P><STRONG><em>Be extremely careful when handling private keys.
260
* When private keys are not kept secret, they lose their ability
261
* to securely authenticate specific entities ... that is a huge
262
* security risk!</em></STRONG>
263
*/
264
public PrivateKey getPrivateKey ()
265
{
266
return privateKey;
267
}
268
269
/**
270
* Returns a self-signed X.509v3 certificate for the public key.
271
* The certificate is immediately valid. No extensions.
272
*
273
* <P>Such certificates normally are used to identify a "Certificate
274
* Authority" (CA). Accordingly, they will not always be accepted by
275
* other parties. However, such certificates are also useful when
276
* you are bootstrapping your security infrastructure, or deploying
277
* system prototypes.
278
*
279
* @param myname X.500 name of the subject (who is also the issuer)
280
* @param firstDate the issue time of the certificate
281
* @param validity how long the certificate should be valid, in seconds
282
* @exception CertificateException on certificate handling errors.
283
* @exception InvalidKeyException on key handling errors.
284
* @exception SignatureException on signature handling errors.
285
* @exception NoSuchAlgorithmException on unrecognized algorithms.
286
* @exception NoSuchProviderException on unrecognized providers.
287
*/
288
public X509Certificate getSelfCertificate (
289
X500Name myname, Date firstDate, long validity)
290
throws CertificateException, InvalidKeyException, SignatureException,
291
NoSuchAlgorithmException, NoSuchProviderException
292
{
293
return getSelfCertificate(myname, firstDate, validity, null);
294
}
295
296
// Like above, plus a CertificateExtensions argument, which can be null.
297
// Create a self-signed certificate, or a certificate that is signed by
298
// a signer when the signer's private key is provided.
299
public X509Certificate getSelfCertificate (X500Name myname, Date firstDate,
300
long validity, CertificateExtensions ext)
301
throws CertificateException, InvalidKeyException, SignatureException,
302
NoSuchAlgorithmException, NoSuchProviderException
303
{
304
X509CertImpl cert;
305
Date lastDate;
306
307
try {
308
lastDate = new Date ();
309
lastDate.setTime (firstDate.getTime () + validity * 1000);
310
Calendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
311
c.setTime(lastDate);
312
if (c.get(Calendar.YEAR) > 9999) {
313
throw new CertificateException("Validity period ends at calendar year " +
314
c.get(Calendar.YEAR) + " which is greater than 9999");
315
}
316
317
CertificateValidity interval =
318
new CertificateValidity(firstDate,lastDate);
319
320
X509CertInfo info = new X509CertInfo();
321
// Add all mandatory attributes
322
info.set(X509CertInfo.VERSION,
323
new CertificateVersion(CertificateVersion.V3));
324
if (prng == null) {
325
prng = new SecureRandom();
326
}
327
info.set(X509CertInfo.SERIAL_NUMBER,
328
CertificateSerialNumber.newRandom64bit(prng));
329
info.set(X509CertInfo.SUBJECT, myname);
330
info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
331
info.set(X509CertInfo.VALIDITY, interval);
332
if (signerFlag) {
333
// use signer's subject name to set the issuer name
334
info.set(X509CertInfo.ISSUER, signerSubjectName);
335
} else {
336
info.set(X509CertInfo.ISSUER, myname);
337
}
338
if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext);
339
340
cert = new X509CertImpl(info);
341
if (signerFlag) {
342
// use signer's private key to sign
343
cert.sign(signerPrivateKey, sigAlg);
344
} else {
345
cert.sign(privateKey, sigAlg);
346
}
347
348
return cert;
349
350
} catch (IOException e) {
351
throw new CertificateEncodingException("getSelfCert: " +
352
e.getMessage());
353
}
354
}
355
356
// Keep the old method
357
public X509Certificate getSelfCertificate (X500Name myname, long validity)
358
throws CertificateException, InvalidKeyException, SignatureException,
359
NoSuchAlgorithmException, NoSuchProviderException
360
{
361
return getSelfCertificate(myname, new Date(), validity);
362
}
363
364
private SecureRandom prng;
365
private String keyType;
366
private String sigAlg;
367
private KeyPairGenerator keyGen;
368
private PublicKey publicKey;
369
private PrivateKey privateKey;
370
private boolean signerFlag;
371
private PrivateKey signerPrivateKey;
372
private X500Name signerSubjectName;
373
}
374
375