Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/security/testlibrary/CertificateBuilder.java
41149 views
1
/*
2
* Copyright (c) 2015, 2020, 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.testlibrary;
27
28
import java.io.*;
29
import java.util.*;
30
import java.security.*;
31
import java.security.cert.X509Certificate;
32
import java.security.cert.CertificateException;
33
import java.security.cert.CertificateFactory;
34
import java.security.cert.Extension;
35
import javax.security.auth.x500.X500Principal;
36
import java.math.BigInteger;
37
38
import sun.security.util.DerOutputStream;
39
import sun.security.util.DerValue;
40
import sun.security.util.ObjectIdentifier;
41
import sun.security.x509.AccessDescription;
42
import sun.security.x509.AlgorithmId;
43
import sun.security.x509.AuthorityInfoAccessExtension;
44
import sun.security.x509.AuthorityKeyIdentifierExtension;
45
import sun.security.x509.SubjectKeyIdentifierExtension;
46
import sun.security.x509.BasicConstraintsExtension;
47
import sun.security.x509.ExtendedKeyUsageExtension;
48
import sun.security.x509.DNSName;
49
import sun.security.x509.GeneralName;
50
import sun.security.x509.GeneralNames;
51
import sun.security.x509.KeyUsageExtension;
52
import sun.security.x509.SerialNumber;
53
import sun.security.x509.SubjectAlternativeNameExtension;
54
import sun.security.x509.URIName;
55
import sun.security.x509.KeyIdentifier;
56
57
/**
58
* Helper class that builds and signs X.509 certificates.
59
*
60
* A CertificateBuilder is created with a default constructor, and then
61
* uses additional public methods to set the public key, desired validity
62
* dates, serial number and extensions. It is expected that the caller will
63
* have generated the necessary key pairs prior to using a CertificateBuilder
64
* to generate certificates.
65
*
66
* The following methods are mandatory before calling build():
67
* <UL>
68
* <LI>{@link #setSubjectName(java.lang.String)}
69
* <LI>{@link #setPublicKey(java.security.PublicKey)}
70
* <LI>{@link #setNotBefore(java.util.Date)} and
71
* {@link #setNotAfter(java.util.Date)}, or
72
* {@link #setValidity(java.util.Date, java.util.Date)}
73
* <LI>{@link #setSerialNumber(java.math.BigInteger)}
74
* </UL><BR>
75
*
76
* Additionally, the caller can either provide a {@link List} of
77
* {@link Extension} objects, or use the helper classes to add specific
78
* extension types.
79
*
80
* When all required and desired parameters are set, the
81
* {@link #build(java.security.cert.X509Certificate, java.security.PrivateKey,
82
* java.lang.String)} method can be used to create the {@link X509Certificate}
83
* object.
84
*
85
* Multiple certificates may be cut from the same settings using subsequent
86
* calls to the build method. Settings may be cleared using the
87
* {@link #reset()} method.
88
*/
89
public class CertificateBuilder {
90
private final CertificateFactory factory;
91
92
private X500Principal subjectName = null;
93
private BigInteger serialNumber = null;
94
private PublicKey publicKey = null;
95
private Date notBefore = null;
96
private Date notAfter = null;
97
private final Map<String, Extension> extensions = new HashMap<>();
98
private byte[] tbsCertBytes;
99
private byte[] signatureBytes;
100
101
/**
102
* Default constructor for a {@code CertificateBuilder} object.
103
*
104
* @throws CertificateException if the underlying {@link CertificateFactory}
105
* cannot be instantiated.
106
*/
107
public CertificateBuilder() throws CertificateException {
108
factory = CertificateFactory.getInstance("X.509");
109
}
110
111
/**
112
* Set the subject name for the certificate.
113
*
114
* @param name An {@link X500Principal} to be used as the subject name
115
* on this certificate.
116
*/
117
public void setSubjectName(X500Principal name) {
118
subjectName = name;
119
}
120
121
/**
122
* Set the subject name for the certificate.
123
*
124
* @param name The subject name in RFC 2253 format
125
*/
126
public void setSubjectName(String name) {
127
subjectName = new X500Principal(name);
128
}
129
130
/**
131
* Set the public key for this certificate.
132
*
133
* @param pubKey The {@link PublicKey} to be used on this certificate.
134
*/
135
public void setPublicKey(PublicKey pubKey) {
136
publicKey = Objects.requireNonNull(pubKey, "Caught null public key");
137
}
138
139
/**
140
* Set the NotBefore date on the certificate.
141
*
142
* @param nbDate A {@link Date} object specifying the start of the
143
* certificate validity period.
144
*/
145
public void setNotBefore(Date nbDate) {
146
Objects.requireNonNull(nbDate, "Caught null notBefore date");
147
notBefore = (Date)nbDate.clone();
148
}
149
150
/**
151
* Set the NotAfter date on the certificate.
152
*
153
* @param naDate A {@link Date} object specifying the end of the
154
* certificate validity period.
155
*/
156
public void setNotAfter(Date naDate) {
157
Objects.requireNonNull(naDate, "Caught null notAfter date");
158
notAfter = (Date)naDate.clone();
159
}
160
161
/**
162
* Set the validity period for the certificate
163
*
164
* @param nbDate A {@link Date} object specifying the start of the
165
* certificate validity period.
166
* @param naDate A {@link Date} object specifying the end of the
167
* certificate validity period.
168
*/
169
public void setValidity(Date nbDate, Date naDate) {
170
setNotBefore(nbDate);
171
setNotAfter(naDate);
172
}
173
174
/**
175
* Set the serial number on the certificate.
176
*
177
* @param serial A serial number in {@link BigInteger} form.
178
*/
179
public void setSerialNumber(BigInteger serial) {
180
Objects.requireNonNull(serial, "Caught null serial number");
181
serialNumber = serial;
182
}
183
184
185
/**
186
* Add a single extension to the certificate.
187
*
188
* @param ext The extension to be added.
189
*/
190
public void addExtension(Extension ext) {
191
Objects.requireNonNull(ext, "Caught null extension");
192
extensions.put(ext.getId(), ext);
193
}
194
195
/**
196
* Add multiple extensions contained in a {@code List}.
197
*
198
* @param extList The {@link List} of extensions to be added to
199
* the certificate.
200
*/
201
public void addExtensions(List<Extension> extList) {
202
Objects.requireNonNull(extList, "Caught null extension list");
203
for (Extension ext : extList) {
204
extensions.put(ext.getId(), ext);
205
}
206
}
207
208
/**
209
* Helper method to add DNSName types for the SAN extension
210
*
211
* @param dnsNames A {@code List} of names to add as DNSName types
212
*
213
* @throws IOException if an encoding error occurs.
214
*/
215
public void addSubjectAltNameDNSExt(List<String> dnsNames) throws IOException {
216
if (!dnsNames.isEmpty()) {
217
GeneralNames gNames = new GeneralNames();
218
for (String name : dnsNames) {
219
gNames.add(new GeneralName(new DNSName(name)));
220
}
221
addExtension(new SubjectAlternativeNameExtension(false,
222
gNames));
223
}
224
}
225
226
/**
227
* Helper method to add one or more OCSP URIs to the Authority Info Access
228
* certificate extension.
229
*
230
* @param locations A list of one or more OCSP responder URIs as strings
231
*
232
* @throws IOException if an encoding error occurs.
233
*/
234
public void addAIAExt(List<String> locations)
235
throws IOException {
236
if (!locations.isEmpty()) {
237
List<AccessDescription> acDescList = new ArrayList<>();
238
for (String ocspUri : locations) {
239
acDescList.add(new AccessDescription(
240
AccessDescription.Ad_OCSP_Id,
241
new GeneralName(new URIName(ocspUri))));
242
}
243
addExtension(new AuthorityInfoAccessExtension(acDescList));
244
}
245
}
246
247
/**
248
* Set a Key Usage extension for the certificate. The extension will
249
* be marked critical.
250
*
251
* @param bitSettings Boolean array for all nine bit settings in the order
252
* documented in RFC 5280 section 4.2.1.3.
253
*
254
* @throws IOException if an encoding error occurs.
255
*/
256
public void addKeyUsageExt(boolean[] bitSettings) throws IOException {
257
addExtension(new KeyUsageExtension(bitSettings));
258
}
259
260
/**
261
* Set the Basic Constraints Extension for a certificate.
262
*
263
* @param crit {@code true} if critical, {@code false} otherwise
264
* @param isCA {@code true} if the extension will be on a CA certificate,
265
* {@code false} otherwise
266
* @param maxPathLen The maximum path length issued by this CA. Values
267
* less than zero will omit this field from the resulting extension and
268
* no path length constraint will be asserted.
269
*
270
* @throws IOException if an encoding error occurs.
271
*/
272
public void addBasicConstraintsExt(boolean crit, boolean isCA,
273
int maxPathLen) throws IOException {
274
addExtension(new BasicConstraintsExtension(crit, isCA, maxPathLen));
275
}
276
277
/**
278
* Add the Authority Key Identifier extension.
279
*
280
* @param authorityCert The certificate of the issuing authority.
281
*
282
* @throws IOException if an encoding error occurs.
283
*/
284
public void addAuthorityKeyIdExt(X509Certificate authorityCert)
285
throws IOException {
286
addAuthorityKeyIdExt(authorityCert.getPublicKey());
287
}
288
289
/**
290
* Add the Authority Key Identifier extension.
291
*
292
* @param authorityKey The public key of the issuing authority.
293
*
294
* @throws IOException if an encoding error occurs.
295
*/
296
public void addAuthorityKeyIdExt(PublicKey authorityKey) throws IOException {
297
KeyIdentifier kid = new KeyIdentifier(authorityKey);
298
addExtension(new AuthorityKeyIdentifierExtension(kid, null, null));
299
}
300
301
/**
302
* Add the Subject Key Identifier extension.
303
*
304
* @param subjectKey The public key to be used in the resulting certificate
305
*
306
* @throws IOException if an encoding error occurs.
307
*/
308
public void addSubjectKeyIdExt(PublicKey subjectKey) throws IOException {
309
byte[] keyIdBytes = new KeyIdentifier(subjectKey).getIdentifier();
310
addExtension(new SubjectKeyIdentifierExtension(keyIdBytes));
311
}
312
313
/**
314
* Add the Extended Key Usage extension.
315
*
316
* @param ekuOids A {@link List} of object identifiers in string form.
317
*
318
* @throws IOException if an encoding error occurs.
319
*/
320
public void addExtendedKeyUsageExt(List<String> ekuOids)
321
throws IOException {
322
if (!ekuOids.isEmpty()) {
323
Vector<ObjectIdentifier> oidVector = new Vector<>();
324
for (String oid : ekuOids) {
325
oidVector.add(ObjectIdentifier.of(oid));
326
}
327
addExtension(new ExtendedKeyUsageExtension(oidVector));
328
}
329
}
330
331
/**
332
* Clear all settings and return the {@code CertificateBuilder} to
333
* its default state.
334
*/
335
public void reset() {
336
extensions.clear();
337
subjectName = null;
338
notBefore = null;
339
notAfter = null;
340
serialNumber = null;
341
publicKey = null;
342
signatureBytes = null;
343
tbsCertBytes = null;
344
}
345
346
/**
347
* Build the certificate.
348
*
349
* @param issuerCert The certificate of the issuing authority, or
350
* {@code null} if the resulting certificate is self-signed.
351
* @param issuerKey The private key of the issuing authority
352
* @param algName The signature algorithm name
353
*
354
* @return The resulting {@link X509Certificate}
355
*
356
* @throws IOException if an encoding error occurs.
357
* @throws CertificateException If the certificate cannot be generated
358
* by the underlying {@link CertificateFactory}
359
* @throws NoSuchAlgorithmException If an invalid signature algorithm
360
* is provided.
361
*/
362
public X509Certificate build(X509Certificate issuerCert,
363
PrivateKey issuerKey, String algName)
364
throws IOException, CertificateException, NoSuchAlgorithmException {
365
// TODO: add some basic checks (key usage, basic constraints maybe)
366
367
AlgorithmId signAlg = AlgorithmId.get(algName);
368
byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, signAlg);
369
ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert);
370
return (X509Certificate)factory.generateCertificate(bais);
371
}
372
373
/**
374
* Encode the contents of the outer-most ASN.1 SEQUENCE:
375
*
376
* <PRE>
377
* Certificate ::= SEQUENCE {
378
* tbsCertificate TBSCertificate,
379
* signatureAlgorithm AlgorithmIdentifier,
380
* signatureValue BIT STRING }
381
* </PRE>
382
*
383
* @param issuerCert The certificate of the issuing authority, or
384
* {@code null} if the resulting certificate is self-signed.
385
* @param issuerKey The private key of the issuing authority
386
* @param signAlg The signature algorithm object
387
*
388
* @return The DER-encoded X.509 certificate
389
*
390
* @throws CertificateException If an error occurs during the
391
* signing process.
392
* @throws IOException if an encoding error occurs.
393
*/
394
private byte[] encodeTopLevel(X509Certificate issuerCert,
395
PrivateKey issuerKey, AlgorithmId signAlg)
396
throws CertificateException, IOException {
397
DerOutputStream outerSeq = new DerOutputStream();
398
DerOutputStream topLevelItems = new DerOutputStream();
399
400
tbsCertBytes = encodeTbsCert(issuerCert, signAlg);
401
topLevelItems.write(tbsCertBytes);
402
try {
403
signatureBytes = signCert(issuerKey, signAlg);
404
} catch (GeneralSecurityException ge) {
405
throw new CertificateException(ge);
406
}
407
signAlg.derEncode(topLevelItems);
408
topLevelItems.putBitString(signatureBytes);
409
outerSeq.write(DerValue.tag_Sequence, topLevelItems);
410
411
return outerSeq.toByteArray();
412
}
413
414
/**
415
* Encode the bytes for the TBSCertificate structure:
416
* <PRE>
417
* TBSCertificate ::= SEQUENCE {
418
* version [0] EXPLICIT Version DEFAULT v1,
419
* serialNumber CertificateSerialNumber,
420
* signature AlgorithmIdentifier,
421
* issuer Name,
422
* validity Validity,
423
* subject Name,
424
* subjectPublicKeyInfo SubjectPublicKeyInfo,
425
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
426
* -- If present, version MUST be v2 or v3
427
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
428
* -- If present, version MUST be v2 or v3
429
* extensions [3] EXPLICIT Extensions OPTIONAL
430
* -- If present, version MUST be v3
431
* }
432
*
433
* @param issuerCert The certificate of the issuing authority, or
434
* {@code null} if the resulting certificate is self-signed.
435
* @param signAlg The signature algorithm object
436
*
437
* @return The DER-encoded bytes for the TBSCertificate structure
438
*
439
* @throws IOException if an encoding error occurs.
440
*/
441
private byte[] encodeTbsCert(X509Certificate issuerCert,
442
AlgorithmId signAlg) throws IOException {
443
DerOutputStream tbsCertSeq = new DerOutputStream();
444
DerOutputStream tbsCertItems = new DerOutputStream();
445
446
// Hardcode to V3
447
byte[] v3int = {0x02, 0x01, 0x02};
448
tbsCertItems.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
449
(byte)0), v3int);
450
451
// Serial Number
452
SerialNumber sn = new SerialNumber(serialNumber);
453
sn.encode(tbsCertItems);
454
455
// Algorithm ID
456
signAlg.derEncode(tbsCertItems);
457
458
// Issuer Name
459
if (issuerCert != null) {
460
tbsCertItems.write(
461
issuerCert.getSubjectX500Principal().getEncoded());
462
} else {
463
// Self-signed
464
tbsCertItems.write(subjectName.getEncoded());
465
}
466
467
// Validity period (set as UTCTime)
468
DerOutputStream valSeq = new DerOutputStream();
469
valSeq.putUTCTime(notBefore);
470
valSeq.putUTCTime(notAfter);
471
tbsCertItems.write(DerValue.tag_Sequence, valSeq);
472
473
// Subject Name
474
tbsCertItems.write(subjectName.getEncoded());
475
476
// SubjectPublicKeyInfo
477
tbsCertItems.write(publicKey.getEncoded());
478
479
// TODO: Extensions!
480
encodeExtensions(tbsCertItems);
481
482
// Wrap it all up in a SEQUENCE and return the bytes
483
tbsCertSeq.write(DerValue.tag_Sequence, tbsCertItems);
484
return tbsCertSeq.toByteArray();
485
}
486
487
/**
488
* Encode the extensions segment for an X.509 Certificate:
489
*
490
* <PRE>
491
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
492
*
493
* Extension ::= SEQUENCE {
494
* extnID OBJECT IDENTIFIER,
495
* critical BOOLEAN DEFAULT FALSE,
496
* extnValue OCTET STRING
497
* -- contains the DER encoding of an ASN.1 value
498
* -- corresponding to the extension type identified
499
* -- by extnID
500
* }
501
* </PRE>
502
*
503
* @param tbsStream The {@code DerOutputStream} that holds the
504
* TBSCertificate contents.
505
*
506
* @throws IOException if an encoding error occurs.
507
*/
508
private void encodeExtensions(DerOutputStream tbsStream)
509
throws IOException {
510
DerOutputStream extSequence = new DerOutputStream();
511
DerOutputStream extItems = new DerOutputStream();
512
513
for (Extension ext : extensions.values()) {
514
ext.encode(extItems);
515
}
516
extSequence.write(DerValue.tag_Sequence, extItems);
517
tbsStream.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
518
(byte)3), extSequence);
519
}
520
521
/**
522
* Digitally sign the X.509 certificate.
523
*
524
* @param issuerKey The private key of the issuing authority
525
* @param signAlg The signature algorithm object
526
*
527
* @return The digital signature bytes.
528
*
529
* @throws GeneralSecurityException If any errors occur during the
530
* digital signature process.
531
*/
532
private byte[] signCert(PrivateKey issuerKey, AlgorithmId signAlg)
533
throws GeneralSecurityException {
534
Signature sig = Signature.getInstance(signAlg.getName());
535
sig.initSign(issuerKey);
536
sig.update(tbsCertBytes);
537
return sig.sign();
538
}
539
}
540
541