1 /*
2 * Copyright 2024 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty.pkitesting;
17
18 import io.netty.util.internal.EmptyArrays;
19 import org.bouncycastle.asn1.ASN1Integer;
20 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
21 import org.bouncycastle.asn1.DERBitString;
22 import org.bouncycastle.asn1.DERIA5String;
23 import org.bouncycastle.asn1.DERUTF8String;
24 import org.bouncycastle.asn1.x500.X500Name;
25 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
26 import org.bouncycastle.asn1.x509.BasicConstraints;
27 import org.bouncycastle.asn1.x509.CRLDistPoint;
28 import org.bouncycastle.asn1.x509.DistributionPoint;
29 import org.bouncycastle.asn1.x509.DistributionPointName;
30 import org.bouncycastle.asn1.x509.Extension;
31 import org.bouncycastle.asn1.x509.ExtensionsGenerator;
32 import org.bouncycastle.asn1.x509.GeneralName;
33 import org.bouncycastle.asn1.x509.GeneralNames;
34 import org.bouncycastle.asn1.x509.KeyPurposeId;
35 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
36 import org.bouncycastle.asn1.x509.Time;
37 import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
38 import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
39
40 import java.io.IOException;
41 import java.io.UncheckedIOException;
42 import java.lang.reflect.Method;
43 import java.math.BigInteger;
44 import java.net.InetAddress;
45 import java.net.URI;
46 import java.net.URISyntaxException;
47 import java.security.GeneralSecurityException;
48 import java.security.KeyPair;
49 import java.security.KeyPairGenerator;
50 import java.security.PrivateKey;
51 import java.security.Provider;
52 import java.security.PublicKey;
53 import java.security.SecureRandom;
54 import java.security.cert.CertificateFactory;
55 import java.security.cert.X509Certificate;
56 import java.security.interfaces.DSAPublicKey;
57 import java.security.interfaces.ECPublicKey;
58 import java.security.interfaces.RSAPublicKey;
59 import java.security.spec.AlgorithmParameterSpec;
60 import java.security.spec.ECGenParameterSpec;
61 import java.security.spec.RSAKeyGenParameterSpec;
62 import java.time.Instant;
63 import java.time.temporal.ChronoUnit;
64 import java.util.ArrayList;
65 import java.util.Date;
66 import java.util.List;
67 import java.util.Objects;
68 import java.util.OptionalInt;
69 import java.util.Set;
70 import java.util.TreeSet;
71 import javax.security.auth.x500.X500Principal;
72
73 import static java.util.Objects.requireNonNull;
74
75 /**
76 * The {@link CertificateBuilder} produce {@link X509Bundle} instances, where the keys use the specified
77 * algorithm, and the certificate have the specified data.
78 * <p>
79 * The builder can make self-signed bundles, or can make bundles that are signed by other bundles to build a verified
80 * certificate path.
81 * <p>
82 * The builder can also make certificate that are invalid in various ways, for testing purpose.
83 * The most typical application is to make a certificate that has already expired or is not yet valid.
84 * <p>
85 * See RFC 5280 for the details of X.509 certificate contents.
86 * <p>
87 * Here is an example where a leaf certificate is created and signed by a self-signed issuer certificate:
88 * <pre>{@code
89 * Instant now = Instant.now();
90 * CertificateBuilder template = new CertificateBuilder()
91 * .notBefore(now.minus(1, DAYS))
92 * .notAfter(now.plus(1, DAYS));
93 * X509Bundle issuer = template.copy()
94 * .subject("CN=testca, OU=dept, O=your-org")
95 * .setKeyUsage(true, KeyUsage.digitalSignature, KeyUsage.keyCertSign)
96 * .setIsCertificateAuthority(true)
97 * .buildSelfSigned();
98 * X509Bundle leaf = template.copy()
99 * .subject("CN=leaf, OU=dept, O=your-org")
100 * .setKeyUsage(true, KeyUsage.digitalSignature)
101 * .addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_SERVER_AUTH)
102 * .addSanDnsName("san-1.leaf.dept.your-org.com")
103 * .buildIssuedBy(issuer);
104 * }</pre>
105 */
106 public final class CertificateBuilder {
107
108 static final String OID_X509_NAME_CONSTRAINTS = "2.5.29.30";
109 static final String OID_PKIX_KP = "1.3.6.1.5.5.7.3";
110 static final String OID_PKIX_KP_SERVER_AUTH = OID_PKIX_KP + ".1";
111 static final String OID_PKIX_KP_CLIENT_AUTH = OID_PKIX_KP + ".2";
112 static final String OID_PKIX_KP_CODE_SIGNING = OID_PKIX_KP + ".3";
113 static final String OID_PKIX_KP_EMAIL_PROTECTION = OID_PKIX_KP + ".4";
114 static final String OID_PKIX_KP_TIME_STAMPING = OID_PKIX_KP + ".8";
115 static final String OID_PKIX_KP_OCSP_SIGNING = OID_PKIX_KP + ".9";
116 static final String OID_KERBEROS_KEY_PURPOSE_CLIENT_AUTH = "1.3.6.1.5.2.3.4";
117 static final String OID_MICROSOFT_SMARTCARD_LOGIN = "1.3.6.1.4.1.311.20.2.2";
118 private static final GeneralName[] EMPTY_GENERAL_NAMES = new GeneralName[0];
119 private static final DistributionPoint[] EMPTY_DIST_POINTS = new DistributionPoint[0];
120 private static final AlgorithmParameterSpec UNSUPPORTED_SPEC = new AlgorithmParameterSpec() {
121 };
122 private static final String UNSUPPORTED_SIGN = "UNSUPPORTED_SIGN";
123
124 Provider provider;
125 SecureRandom random;
126 Algorithm algorithm = Algorithm.ecp256;
127 Instant notBefore = Instant.now().minus(1, ChronoUnit.DAYS);
128 Instant notAfter = Instant.now().plus(1, ChronoUnit.DAYS);
129 List<BuilderCallback> modifierCallbacks = new ArrayList<>();
130 List<GeneralName> subjectAlternativeNames = new ArrayList<>();
131 List<DistributionPoint> crlDistributionPoints = new ArrayList<>();
132 BigInteger serial;
133 X500Principal subject;
134 boolean isCertificateAuthority;
135 OptionalInt pathLengthConstraint = OptionalInt.empty();
136 PublicKey publicKey;
137 Set<String> extendedKeyUsage = new TreeSet<>();
138 Extension keyUsage;
139
140 /**
141 * Create a new certificate builder with a default configuration.
142 * Unless specified otherwise, the builder will produce bundles that use the
143 * {@linkplain Algorithm#ecp256 NIST EC-P 256} key algorithm,
144 * and the certificates will be valid as of yesterday and expire tomorrow.
145 */
146 public CertificateBuilder() {
147 }
148
149 /**
150 * Produce a copy of the current state in this certificate builder.
151 * @return A copy of this certificate builder.
152 */
153 public CertificateBuilder copy() {
154 CertificateBuilder copy = new CertificateBuilder();
155 copy.random = random;
156 copy.algorithm = algorithm;
157 copy.notBefore = notBefore;
158 copy.notAfter = notAfter;
159 copy.modifierCallbacks = new ArrayList<>(modifierCallbacks);
160 copy.subjectAlternativeNames = new ArrayList<>(subjectAlternativeNames);
161 copy.crlDistributionPoints = new ArrayList<>(crlDistributionPoints);
162 copy.serial = serial;
163 copy.subject = subject;
164 copy.isCertificateAuthority = isCertificateAuthority;
165 copy.pathLengthConstraint = pathLengthConstraint;
166 copy.publicKey = publicKey;
167 copy.keyUsage = keyUsage;
168 copy.extendedKeyUsage = new TreeSet<>(extendedKeyUsage);
169 copy.provider = provider;
170 return copy;
171 }
172
173 /**
174 * Set the {@link Provider} instance to use when generating keys.
175 * @param provider The provider instance to use.
176 * @return This certificate builder.
177 */
178 public CertificateBuilder provider(Provider provider) {
179 this.provider = provider;
180 return this;
181 }
182
183 /**
184 * Set the {@link SecureRandom} instance to use when generating keys.
185 * @param secureRandom The secure random instance to use.
186 * @return This certificate builder.
187 */
188 public CertificateBuilder secureRandom(SecureRandom secureRandom) {
189 random = requireNonNull(secureRandom);
190 return this;
191 }
192
193 /**
194 * Set the not-before field of the certificate. The certificate will not be valid before this time.
195 * @param instant The not-before time.
196 * @return This certificate builder.
197 */
198 public CertificateBuilder notBefore(Instant instant) {
199 notBefore = requireNonNull(instant);
200 return this;
201 }
202
203 /**
204 * Set the not-after field of the certificate. The certificate will not be valid after this time.
205 * @param instant The not-after time.
206 * @return This certificate builder.
207 */
208 public CertificateBuilder notAfter(Instant instant) {
209 notAfter = requireNonNull(instant);
210 return this;
211 }
212
213 /**
214 * Set the specific serial number to use in the certificate.
215 * One will be generated randomly, if none is specified.
216 * @param serial The serial number to use, or {@code null}.
217 * @return This certificate builder.
218 */
219 public CertificateBuilder serial(BigInteger serial) {
220 this.serial = serial;
221 return this;
222 }
223
224 /**
225 * Set the fully-qualified domain name (an X.500 name) as the subject of the certificate.
226 * @param fqdn The subject name to use.
227 * @return This certificate builder.
228 */
229 public CertificateBuilder subject(String fqdn) {
230 subject = new X500Principal(requireNonNull(fqdn));
231 return this;
232 }
233
234 /**
235 * Set the subject name of the certificate to the given {@link X500Principal}.
236 * @param name The subject name to use.
237 * @return This certificate builder.
238 */
239 public CertificateBuilder subject(X500Principal name) {
240 subject = requireNonNull(name);
241 return this;
242 }
243
244 /**
245 * Add an Other Name to the Subject Alternative Names, of the given OID type, and with the given encoded value.
246 * The type and value will be wrapped in a SEQUENCE.
247 * @param typeOid The OID type of the Other Name value.
248 * @param encodedValue The encoded Other Name value.
249 * @return This certificate builder.
250 */
251 public CertificateBuilder addSanOtherName(String typeOid, byte[] encodedValue) {
252 subjectAlternativeNames.add(GeneralNameUtils.otherName(typeOid, encodedValue));
253 return this;
254 }
255
256 /**
257 * Add an RFC 822 name to the Subject Alternative Names.
258 * The RFC 822 standard is the obsolete specification for email, so these SANs are email addresses.
259 * @param name The email address to add to the SANs.
260 * @return This certificate builder.
261 */
262 public CertificateBuilder addSanRfc822Name(String name) {
263 subjectAlternativeNames.add(GeneralNameUtils.rfc822Name(name));
264 return this;
265 }
266
267 /**
268 * Add a DNS name to the Subject Alternate Names.
269 * @param dns The DNS name to add.
270 * @return This certificate builder.
271 */
272 public CertificateBuilder addSanDnsName(String dns) {
273 if (dns.trim().isEmpty()) {
274 throw new IllegalArgumentException("Blank DNS SANs are forbidden by RFC 5280, Section 4.2.1.6.");
275 }
276 subjectAlternativeNames.add(GeneralNameUtils.dnsName(dns));
277 return this;
278 }
279
280 // x400Address support intentionally omitted; not in common use.
281
282 /**
283 * Add a Directory Name to the Subject Alternative Names.
284 * These are LDAP directory paths.
285 * @param dirName The directory name to add to the SANs.
286 * @return This certificate builder.
287 */
288 public CertificateBuilder addSanDirectoryName(String dirName) {
289 subjectAlternativeNames.add(GeneralNameUtils.directoryName(dirName));
290 return this;
291 }
292
293 // ediPartyName support intentionally omitted; not in common use.
294
295 /**
296 * Add a URI name to the Subject Alternative Names.
297 * @param uri The URI to add to the SANs.
298 * @return This certificate builder.
299 */
300 public CertificateBuilder addSanUriName(String uri) throws URISyntaxException {
301 subjectAlternativeNames.add(GeneralNameUtils.uriName(uri));
302 return this;
303 }
304
305 /**
306 * Add a URI name to the Subject Alternative Names.
307 * @param uri The URI to add to the SANs.
308 * @return This certificate builder.
309 */
310 public CertificateBuilder addSanUriName(URI uri) {
311 subjectAlternativeNames.add(GeneralNameUtils.uriName(uri));
312 return this;
313 }
314
315 /**
316 * Add an IP address to the Subject Alternative Names.
317 * IPv4 and IPv6 addresses are both supported and converted to their correct encoding.
318 * @param ipAddress The IP address to add to the SANs.
319 * @return This certificate builder.
320 */
321 public CertificateBuilder addSanIpAddress(String ipAddress) {
322 subjectAlternativeNames.add(GeneralNameUtils.ipAddress(ipAddress));
323 return this;
324 }
325
326 /**
327 * Add an IP address to the Subject Alternative Names.
328 * IPv4 and IPv6 addresses are both supported and converted to their correct encoding.
329 * @param ipAddress The IP address to add to the SANs.
330 * @return This certificate builder.
331 */
332 public CertificateBuilder addSanIpAddress(InetAddress ipAddress) {
333 subjectAlternativeNames.add(GeneralNameUtils.ipAddress(ipAddress.getHostAddress()));
334 return this;
335 }
336
337 /**
338 * Add a registeredID to the Subject Alternative Names.
339 * A registeredID is an OBJECT IDENTIFIER, or OID, in ASN.1 speak.
340 * @param oid The OID to add to the SANs.
341 * @return This certificate builder.
342 */
343 public CertificateBuilder addSanRegisteredId(String oid) {
344 subjectAlternativeNames.add(GeneralNameUtils.registeredId(oid));
345 return this;
346 }
347
348 /**
349 * Add a URI distribution point for a certificate revocation list.
350 * <p>
351 * If you are testing certificate revocation using the {@link RevocationServer},
352 * you would obtain this URI from {@link RevocationServer#getCrlUri(X509Bundle)} with your intended issuer
353 * certificate bundle.
354 *
355 * @param uri The URI for the CRL file.
356 * @return This certificate builder.
357 */
358 public CertificateBuilder addCrlDistributionPoint(URI uri) {
359 GeneralName fullName = GeneralNameUtils.uriName(uri);
360 crlDistributionPoints.add(new DistributionPoint(
361 new DistributionPointName(new GeneralNames(fullName)),
362 null,
363 null));
364 return this;
365 }
366
367 /**
368 * Add a URI distribution point for a certificate revocation list.
369 * <p>
370 * If you are testing certificate revocation using the {@link RevocationServer},
371 * you would obtain this URI from {@link RevocationServer#getCrlUri(X509Bundle)} with your intended issuer
372 * certificate bundle.
373 *
374 * @param uri The URI for the CRL file.
375 * @param issuer The issuer that signs the CRL file.
376 * This MUST be {@code null} if the CRL issuer is also the issuer of the certificate being built.
377 * Otherwise, if this certificate and the CRL will be signed by different issuers, then this MUST be the subject
378 * name of the CRL signing certificate.
379 * @return This certificate builder.
380 */
381 public CertificateBuilder addCrlDistributionPoint(URI uri, X500Principal issuer) {
382 GeneralName fullName = GeneralNameUtils.uriName(uri);
383 GeneralName issuerName = GeneralNameUtils.directoryName(issuer);
384 crlDistributionPoints.add(new DistributionPoint(
385 new DistributionPointName(new GeneralNames(fullName)),
386 null,
387 new GeneralNames(issuerName)));
388 return this;
389 }
390
391 /**
392 * Set the certificate authority field.
393 * If this is set to {@code true}, then this builder can build self-signed certificates, and those certifiactes
394 * can be used to sign other certificates.
395 * @param isCA {@code true} if this builder should make CA certificates.
396 * @return This certificate builder.
397 */
398 public CertificateBuilder setIsCertificateAuthority(boolean isCA) {
399 isCertificateAuthority = isCA;
400 return this;
401 }
402
403 /**
404 * Certificate Authority certificates may impose a limit to the length of the verified certificate path they permit.
405 * @param pathLengthConstraint The maximum verified path length, if any.
406 * @return This certificate builder.
407 */
408 public CertificateBuilder setPathLengthConstraint(OptionalInt pathLengthConstraint) {
409 this.pathLengthConstraint = requireNonNull(pathLengthConstraint, "pathLengthConstraint");
410 return this;
411 }
412
413 /**
414 * Set the key algorithm to use. This also determines how certificates are signed.
415 * @param algorithm The algorithm to use when generating the private key.
416 * @return This certificate builder.
417 */
418 public CertificateBuilder algorithm(Algorithm algorithm) {
419 requireNonNull(algorithm, "algorithm");
420 if (algorithm.parameterSpec == UNSUPPORTED_SPEC) {
421 throw new UnsupportedOperationException("This algorithm is not supported: " + algorithm);
422 }
423 this.algorithm = algorithm;
424 return this;
425 }
426
427 /**
428 * Make this certificate builder use the {@linkplain Algorithm#ecp256 NIST EC-P 256} elliptic curve key algorithm.
429 * This algorithm provides a good balance between security, compatibility, performance, and key & signature sizes.
430 * @return This certificate builder.
431 * @see Algorithm#ecp256
432 */
433 public CertificateBuilder ecp256() {
434 return algorithm(Algorithm.ecp256);
435 }
436
437 /**
438 * Make this certificate builder use the {@linkplain Algorithm#rsa2048 2048-bit RSA} encryption and signing
439 * algorithm. This algorithm provides maximum compatibility, but keys are large and slow to generate.
440 * @return This certificate builder.
441 * @see Algorithm#rsa2048
442 */
443 public CertificateBuilder rsa2048() {
444 return algorithm(Algorithm.rsa2048);
445 }
446
447 /**
448 * Instruct the certificate builder to not generate its own key pair, but to instead create a certificate that
449 * uses the given public key.
450 * <p>
451 * This method is useful if you want to use an existing key-pair, e.g. to emulate a certificate authority
452 * responding to a Certificate Signing Request (CSR).
453 * <p>
454 * If the given public key is {@code null} (the default) then a new key-pair will be generated instead.
455 *
456 * @param key The public key to wrap in a certificate.
457 * @return This certificate builder.
458 */
459 public CertificateBuilder publicKey(PublicKey key) {
460 publicKey = key;
461 return this;
462 }
463
464 private CertificateBuilder addExtension(String identifierOid, boolean critical, byte[] value) {
465 requireNonNull(identifierOid, "identifierOid");
466 requireNonNull(value, "value");
467 modifierCallbacks.add(builder -> {
468 builder.addExtension(new Extension(
469 new ASN1ObjectIdentifier(identifierOid),
470 critical,
471 value));
472 });
473 return this;
474 }
475
476 /**
477 * Add a custom extension to the certificate, with the given OID, criticality flag, and DER-encoded contents.
478 * @param identifierOID The OID identifying the extension.
479 * @param critical {@code true} if the extension is critical, otherwise {@code false}.
480 * Certificate systems MUST reject certificates with critical extensions they don't recognize.
481 * @param contents The DER-encoded extension contents.
482 * @return This certificate builder.
483 */
484 public CertificateBuilder addExtensionOctetString(String identifierOID, boolean critical, byte[] contents) {
485 requireNonNull(identifierOID, "identifierOID");
486 requireNonNull(contents, "contents");
487 modifierCallbacks.add(builder -> {
488 builder.addExtension(new Extension(
489 new ASN1ObjectIdentifier(identifierOID),
490 critical,
491 contents));
492 });
493 return this;
494 }
495
496 /**
497 * Add a custom DER-encoded ASN.1 UTF-8 string extension to the certificate, with the given OID, criticality,
498 * and string value.
499 * The string will be converted to its proper binary encoding by this method.
500 * @param identifierOID The OID identifying the extension.
501 * @param critical {@code true} if the extension is critical, otherwise {@code false}.
502 * Certificate systems MUST reject certificates with critical extensions they don't recognize.
503 * @param value The string value.
504 * @return This certificate builder.
505 */
506 public CertificateBuilder addExtensionUtf8String(String identifierOID, boolean critical, String value) {
507 try {
508 return addExtension(identifierOID, critical, new DERUTF8String(value).getEncoded("DER"));
509 } catch (IOException e) {
510 throw new UncheckedIOException(e);
511 }
512 }
513
514 /**
515 * Add a custom DER-encoded ASN.1 IA5String (an ASCII string) extension to the certificate, with the given OID,
516 * criticality, and string value.
517 * The string will be converted to its proper binary encoding by this method.
518 * @param identifierOID The OID identifying the extension.
519 * @param critical {@code true} if the extension is critical, otherwise {@code false}.
520 * Certificate systems MUST reject certificates with critical extensions they don't recognize.
521 * @param value The string value.
522 * @return This certificate builder.
523 */
524 public CertificateBuilder addExtensionAsciiString(String identifierOID, boolean critical, String value) {
525 try {
526 return addExtension(identifierOID, critical, new DERIA5String(value).getEncoded("DER"));
527 } catch (IOException e) {
528 throw new UncheckedIOException(e);
529 }
530 }
531
532 /**
533 * The key usage specify the intended usages for which the certificate has been issued.
534 * Some are overlapping, some are deprecated, and some are implied by usage.
535 * <p>
536 * For Certificate Authority usage, the important ones are {@link KeyUsage#keyCertSign}
537 * and {@link KeyUsage#cRLSign}.
538 * <p>
539 * Any certificate that has {@link KeyUsage#keyCertSign} must also have {@link #setIsCertificateAuthority(boolean)}
540 * set to {@code true}.
541 *
542 * @param critical {@code true} if certificate recipients are required to understand all the set bits,
543 * otherwise {@code false}.
544 * @param keyUsages The key usages to set.
545 * @return This certificate builder.
546 */
547 public CertificateBuilder setKeyUsage(boolean critical, KeyUsage... keyUsages) {
548 int maxBit = 0;
549 for (KeyUsage usage : keyUsages) {
550 maxBit = Math.max(usage.bitId, maxBit);
551 }
552 boolean[] bits = new boolean[maxBit + 1];
553 for (KeyUsage usage : keyUsages) {
554 bits[usage.bitId] = true;
555 }
556 int padding = 8 - bits.length % 8;
557 int lenBytes = bits.length / 8 + 1;
558 if (padding == 8) {
559 padding = 0;
560 lenBytes--;
561 }
562 byte[] bytes = new byte[lenBytes];
563 for (int i = 0; i < bits.length; i++) {
564 if (bits[i]) {
565 int byteIndex = i / 8;
566 int bitIndex = i % 8;
567 bytes[byteIndex] |= (byte) (0x80 >>> bitIndex);
568 }
569 }
570
571 try {
572 keyUsage = new Extension(
573 Extension.keyUsage,
574 critical,
575 new DERBitString(bytes, padding).getEncoded("DER"));
576 } catch (IOException e) {
577 throw new UncheckedIOException(e);
578 }
579 return this;
580 }
581
582 /**
583 * Add the given OID to the list of extended key usages.
584 * @param oid The OID to add.
585 * @return This certificate builder.
586 * @see ExtendedKeyUsage
587 * @see #addExtendedKeyUsage(ExtendedKeyUsage)
588 */
589 public CertificateBuilder addExtendedKeyUsage(String oid) {
590 extendedKeyUsage.add(oid);
591 return this;
592 }
593
594 /**
595 * Add the given {@link ExtendedKeyUsage} to the list of extended key usages.
596 * @param keyUsage The extended key usage to add.
597 * @return This certificate builder.
598 */
599 public CertificateBuilder addExtendedKeyUsage(ExtendedKeyUsage keyUsage) {
600 extendedKeyUsage.add(keyUsage.getOid());
601 return this;
602 }
603
604 /**
605 * Add server-authentication to the list of extended key usages.
606 * @return This certificate builder.
607 */
608 public CertificateBuilder addExtendedKeyUsageServerAuth() {
609 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_SERVER_AUTH);
610 }
611
612 /**
613 * Add client-authentication to the list of extended key usages.
614 * @return This certificate builder.
615 */
616 public CertificateBuilder addExtendedKeyUsageClientAuth() {
617 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_CLIENT_AUTH);
618 }
619
620 /**
621 * Add code signing to the list of extended key usages.
622 * @return This certificate builder.
623 */
624 public CertificateBuilder addExtendedKeyUsageCodeSigning() {
625 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_CODE_SIGNING);
626 }
627
628 /**
629 * Add email protection to the list of extended key usages.
630 * @return This certificate builder.
631 */
632 public CertificateBuilder addExtendedKeyUsageEmailProtection() {
633 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_EMAIL_PROTECTION);
634 }
635
636 /**
637 * Add time-stamping to the list of extended key usages.
638 * @return This certificate builder.
639 */
640 public CertificateBuilder addExtendedKeyUsageTimeStamping() {
641 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_TIME_STAMPING);
642 }
643
644 /**
645 * Add OCSP signing to the list of extended key usages.
646 * @return This certificate builder.
647 */
648 public CertificateBuilder addExtendedKeyUsageOcspSigning() {
649 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_OCSP_SIGNING);
650 }
651
652 /**
653 * Add Kerberos client authentication to the list of extended key usages.
654 * @return This certificate builder.
655 */
656 public CertificateBuilder addExtendedKeyUsageKerberosClientAuth() {
657 return addExtendedKeyUsage(ExtendedKeyUsage.KERBEROS_KEY_PURPOSE_CLIENT_AUTH);
658 }
659
660 /**
661 * Add Microsoft smartcard login to the list of extended key usages.
662 * @return This certificate builder.
663 */
664 public CertificateBuilder addExtendedKeyUsageMicrosoftSmartcardLogin() {
665 return addExtendedKeyUsage(ExtendedKeyUsage.MICROSOFT_SMARTCARD_LOGIN);
666 }
667
668 /**
669 * Build a {@link X509Bundle} with a self-signed certificate.
670 * @return The newly created bundle.
671 * @throws Exception If something went wrong in the process.
672 */
673 public X509Bundle buildSelfSigned() throws Exception {
674 if (publicKey != null) {
675 throw new IllegalStateException("Cannot create a self-signed certificate with a public key from a CSR.");
676 }
677 if (!algorithm.supportSigning()) {
678 throw new IllegalStateException("Cannot create a self-signed certificate with a " +
679 "key algorithm that does not support signing: " + algorithm);
680 }
681 KeyPair keyPair = generateKeyPair(provider);
682
683 V3TBSCertificateGenerator generator = createCertBuilder(subject, subject, keyPair, algorithm.signatureType);
684
685 addExtensions(generator);
686
687 Signed signed = new Signed(tbsCertToBytes(generator), algorithm.signatureType, keyPair.getPrivate());
688 CertificateFactory factory = CertificateFactory.getInstance("X.509");
689 X509Certificate cert = (X509Certificate) factory.generateCertificate(signed.toInputStream(provider));
690 return X509Bundle.fromRootCertificateAuthority(cert, keyPair);
691 }
692
693 /**
694 * Build a {@link X509Bundle} with a certificate signed by the given issuer bundle.
695 * The signing algorithm used will be derived from the issuers public key.
696 * @return The newly created bundle.
697 * @throws Exception If something went wrong in the process.
698 */
699 public X509Bundle buildIssuedBy(X509Bundle issuerBundle) throws Exception {
700 String issuerSignAlgorithm = preferredSignatureAlgorithm(issuerBundle.getCertificate().getPublicKey());
701 return buildIssuedBy(issuerBundle, issuerSignAlgorithm);
702 }
703
704 /**
705 * Build a {@link X509Bundle} with a certificate signed by the given issuer bundle, using the specified
706 * signing algorithm.
707 * @return The newly created bundle.
708 * @throws Exception If something went wrong in the process.
709 */
710 public X509Bundle buildIssuedBy(X509Bundle issuerBundle, String signAlg) throws Exception {
711 final KeyPair keyPair;
712 if (publicKey == null) {
713 keyPair = generateKeyPair(provider);
714 } else {
715 keyPair = new KeyPair(publicKey, null);
716 }
717
718 X500Principal issuerPrincipal = issuerBundle.getCertificate().getSubjectX500Principal();
719 V3TBSCertificateGenerator generator = createCertBuilder(issuerPrincipal, subject, keyPair, signAlg);
720
721 addExtensions(generator);
722
723 PrivateKey issuerPrivateKey = issuerBundle.getKeyPair().getPrivate();
724 if (issuerPrivateKey == null) {
725 throw new IllegalArgumentException(
726 "Cannot sign certificate with issuer bundle that does not have a private key.");
727 }
728 Signed signed = new Signed(tbsCertToBytes(generator), signAlg, issuerPrivateKey);
729 CertificateFactory factory = CertificateFactory.getInstance("X.509");
730 X509Certificate cert = (X509Certificate) factory.generateCertificate(signed.toInputStream(provider));
731 X509Certificate[] issuerPath = issuerBundle.getCertificatePath();
732 X509Certificate[] path = new X509Certificate[issuerPath.length + 1];
733 path[0] = cert;
734 System.arraycopy(issuerPath, 0, path, 1, issuerPath.length);
735 return X509Bundle.fromCertificatePath(path, issuerBundle.getRootCertificate(), keyPair);
736 }
737
738 private static String preferredSignatureAlgorithm(PublicKey key) {
739 if (key instanceof RSAPublicKey) {
740 RSAPublicKey rsa = (RSAPublicKey) key;
741 if (rsa.getModulus().bitLength() < 4096) {
742 return "SHA256withRSA";
743 }
744 return "SHA384withRSA";
745 }
746 if (key instanceof ECPublicKey) {
747 ECPublicKey ec = (ECPublicKey) key;
748 int size = ec.getW().getAffineX().bitLength();
749 // Note: the coords are not guaranteed to use up all available bits, hence less-than-or-equal checks.
750 if (size <= 256) {
751 return "SHA256withECDSA";
752 }
753 if (size <= 384) {
754 return "SHA384withECDSA";
755 }
756 return "SHA512withECDSA";
757 }
758 if (key instanceof DSAPublicKey) {
759 throw new IllegalArgumentException("DSA keys are not supported because they are obsolete");
760 }
761 String keyAlgorithm = key.getAlgorithm();
762 if ("Ed25519".equals(keyAlgorithm) || "1.3.101.112".equals(keyAlgorithm)) {
763 return "Ed25519";
764 }
765 if ("Ed448".equals(keyAlgorithm) || "1.3.101.113".equals(keyAlgorithm)) {
766 return "Ed448";
767 }
768 if ("EdDSA".equals(keyAlgorithm)) {
769 byte[] encoded = key.getEncoded();
770 if (encoded.length <= 44) {
771 return "Ed25519";
772 }
773 if (encoded.length <= 69) {
774 return "Ed448";
775 }
776 }
777 if ("ML-DSA".equals(keyAlgorithm)) {
778 try {
779 Method getParams = Class.forName("java.security.AsymmetricKey").getMethod("getParams");
780 Object params = getParams.invoke(key);
781 Method getName = params.getClass().getMethod("getName");
782 return (String) getName.invoke(params);
783 } catch (Exception e) {
784 throw new IllegalArgumentException("Cannot get algorithm name for ML-DSA key", e);
785 }
786 }
787 if ("ML-KEM".equals(keyAlgorithm)) {
788 throw new IllegalArgumentException("ML-KEM keys cannot be used for signing");
789 }
790 throw new IllegalArgumentException("Don't know what signature algorithm is best for " + key);
791 }
792
793 private KeyPair generateKeyPair(Provider provider) throws GeneralSecurityException {
794 return algorithm.generateKeyPair(getSecureRandom(), provider);
795 }
796
797 private V3TBSCertificateGenerator createCertBuilder(
798 X500Principal issuer, X500Principal subject, KeyPair keyPair, String signAlg) {
799 BigInteger serial = this.serial != null ? this.serial : new BigInteger(159, getSecureRandom());
800 PublicKey pubKey = keyPair.getPublic();
801
802 V3TBSCertificateGenerator generator = new V3TBSCertificateGenerator();
803 generator.setIssuer(X500Name.getInstance(issuer.getEncoded()));
804 if (subject != null) {
805 generator.setSubject(X500Name.getInstance(subject.getEncoded()));
806 }
807 generator.setSerialNumber(new ASN1Integer(serial));
808 generator.setSignature(new AlgorithmIdentifier(new ASN1ObjectIdentifier(
809 Algorithms.oidForAlgorithmName(signAlg))));
810 generator.setStartDate(new Time(Date.from(notBefore)));
811 generator.setEndDate(new Time(Date.from(notAfter)));
812 generator.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()));
813 return generator;
814 }
815
816 private static byte[] tbsCertToBytes(V3TBSCertificateGenerator generator) {
817 try {
818 return generator.generateTBSCertificate().getEncoded("DER");
819 } catch (IOException e) {
820 throw new UncheckedIOException(e);
821 }
822 }
823
824 private SecureRandom getSecureRandom() {
825 SecureRandom rng = random;
826 if (rng == null) {
827 rng = SecureRandomHolder.RANDOM;
828 }
829 return rng;
830 }
831
832 private void addExtensions(V3TBSCertificateGenerator tbsCert) throws Exception {
833 ExtensionsGenerator generator = new ExtensionsGenerator();
834 if (isCertificateAuthority) {
835 final BasicConstraints basicConstraints;
836 if (pathLengthConstraint.isPresent()) {
837 basicConstraints = new BasicConstraints(pathLengthConstraint.getAsInt());
838 } else {
839 basicConstraints = new BasicConstraints(true);
840 }
841 final byte[] basicConstraintsBytes = basicConstraints.getEncoded("DER");
842 generator.addExtension(new Extension(Extension.basicConstraints, true, basicConstraintsBytes));
843 }
844 if (keyUsage != null) {
845 generator.addExtension(keyUsage);
846 }
847
848 if (!extendedKeyUsage.isEmpty()) {
849 KeyPurposeId[] usages = new KeyPurposeId[extendedKeyUsage.size()];
850 String[] usagesStrings = extendedKeyUsage.toArray(EmptyArrays.EMPTY_STRINGS);
851 for (int i = 0; i < usagesStrings.length; i++) {
852 usages[i] = KeyPurposeId.getInstance(new ASN1ObjectIdentifier(usagesStrings[i]));
853 }
854 byte[] der = new org.bouncycastle.asn1.x509.ExtendedKeyUsage(usages).getEncoded("DER");
855 generator.addExtension(new Extension(Extension.extendedKeyUsage, false, der));
856 }
857
858 if (!subjectAlternativeNames.isEmpty()) {
859 // SAN is critical extension if subject is empty sequence:
860 boolean critical = subject.getName().isEmpty();
861 byte[] result;
862 GeneralNames generalNames = new GeneralNames(subjectAlternativeNames.toArray(EMPTY_GENERAL_NAMES));
863 try {
864 result = generalNames.getEncoded("DER");
865 } catch (IOException e) {
866 throw new UncheckedIOException(e);
867 }
868 generator.addExtension(new Extension(Extension.subjectAlternativeName, critical, result));
869 }
870
871 if (!crlDistributionPoints.isEmpty()) {
872 generator.addExtension(Extension.create(
873 Extension.cRLDistributionPoints,
874 false,
875 new CRLDistPoint(crlDistributionPoints.toArray(EMPTY_DIST_POINTS))));
876 }
877
878 for (BuilderCallback callback : modifierCallbacks) {
879 callback.modify(generator);
880 }
881
882 if (!generator.isEmpty()) {
883 tbsCert.setExtensions(generator.generate());
884 }
885 }
886
887 /**
888 * The {@link Algorithm} enum encapsulates both the key type, key generation parameters, and the signature
889 * algorithm to use.
890 */
891 public enum Algorithm {
892 /**
893 * The NIST P-256 elliptic curve algorithm, offer fast key generation, signing, and verification,
894 * with small keys and signatures, at 128-bits of security strength.
895 * <p>
896 * This algorithm is older than the Edwards curves, and are more widely supported.
897 */
898 ecp256("EC", new ECGenParameterSpec("secp256r1"), "SHA256withECDSA"),
899 /**
900 * The NIST P-384 elliptic curve algorithm, offer fast key generation, signing, and verification,
901 * with small keys and signatures, at 192-bits of security strength.
902 * <p>
903 * This algorithm is older than the Edwards curves, and are more widely supported.
904 */
905 ecp384("EC", new ECGenParameterSpec("secp384r1"), "SHA384withECDSA"),
906 /**
907 * The 2048-bit RSA algorithm offer roughly 112-bits of security strength, at the cost of large keys
908 * and slightly expensive key generation.
909 * <p>
910 * This algorithm enjoy the widest support and compatibility, though.
911 */
912 rsa2048("RSA", new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4), "SHA256withRSA"),
913 /**
914 * The 3072-bit RSA algorithm offer roughly 128-bits of security strength, at the cost of large keys
915 * and fairly expensive key generation.
916 * <p>
917 * RSA enjoy pretty wide compatibility, though not all systems support keys this large.
918 */
919 rsa3072("RSA", new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4), "SHA256withRSA"),
920 /**
921 * The 4096-bit RSA algorithm offer roughly greater than 128-bits of security strength,
922 * at the cost of large keys and very expensive key generation.
923 * <p>
924 * RSA enjoy pretty wide compatibility, though not all systems support keys this large.
925 */
926 rsa4096("RSA", new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4), "SHA384withRSA"),
927 /**
928 * The 8192-bit RSA algorithm offer roughly greater than 192-bits of security strength,
929 * at the cost of very large keys and extremely expensive key generation.
930 * <p>
931 * RSA enjoy pretty wide compatibility, though not all systems support keys this large.
932 */
933 rsa8192("RSA", new RSAKeyGenParameterSpec(8192, RSAKeyGenParameterSpec.F4), "SHA384withRSA"),
934 /**
935 * The Ed25519 algorithm offer fast key generation, signing, and verification,
936 * with very small keys and signatures, at 128-bits of security strength.
937 * <p>
938 * This algorithm was added in Java 15, and may not be supported everywhere.
939 */
940 ed25519("Ed25519", namedParameterSpec("Ed25519"), "Ed25519"),
941 /**
942 * The Ed448 algorithm offer fast key generation, signing, and verification,
943 * with small keys and signatures, at 224-bits of security strength.
944 * <p>
945 * This algorithm was added in Java 15, and may not be supported everywhere.
946 */
947 ed448("Ed448", namedParameterSpec("Ed448"), "Ed448"),
948 /**
949 * The ML-DSA-44 algorithm is the NIST FIPS 204 version of the post-quantum Dilithium algorithm.
950 * It has 128-bits of classical security strength, and is claimed to meet NIST Level 2
951 * quantum security strength (equivalent to finding a SHA-256 collision).
952 * <p>
953 * This algorithm was added in Java 24, and may not be supported everywhere.
954 */
955 mlDsa44("ML-DSA", namedParameterSpec("ML-DSA-44"), "ML-DSA-44"),
956 /**
957 * The ML-DSA-65 algorithm is the NIST FIPS 204 version of the post-quantum Dilithium algorithm.
958 * It has 192-bits of classical security strength, and is claimed to meet NIST Level 3
959 * quantum security strength (equivalent to finding the key for an AES-192 block).
960 * <p>
961 * This algorithm was added in Java 24, and may not be supported everywhere.
962 */
963 mlDsa65("ML-DSA", namedParameterSpec("ML-DSA-65"), "ML-DSA-65"),
964 /**
965 * The ML-DSA-87 algorithm is the NIST FIPS 204 version of the post-quantum Dilithium algorithm.
966 * It has 256-bits of classical security strength, and is claimed to meet NIST Level 5
967 * quantum security strength (equivalent to finding the key for an AES-256 block).
968 * <p>
969 * This algorithm was added in Java 24, and may not be supported everywhere.
970 */
971 mlDsa87("ML-DSA", namedParameterSpec("ML-DSA-87"), "ML-DSA-87"),
972 /**
973 * The ML-KEM-512 algorithm is the NIST FIPS 203 version of the post-quantum Kyber algorithm.
974 * It has 128-bits of classical security strength, and is claimed to meet NIST Level 1
975 * quantum security strength (equivalent to finding the key for an AES-1128 block).
976 * <p>
977 * This algorithm was added in Java 24, and may not be supported everywhere.
978 */
979 mlKem512("ML-KEM", namedParameterSpec("ML-KEM-512"), UNSUPPORTED_SIGN),
980 /**
981 * The ML-KEM-768 algorithm is the NIST FIPS 203 version of the post-quantum Kyber algorithm.
982 * It has 192-bits of classical security strength, and is claimed to meet NIST Level 3
983 * quantum security strength (equivalent to finding the key for an AES-192 block).
984 * <p>
985 * This algorithm was added in Java 24, and may not be supported everywhere.
986 */
987 mlKem768("ML-KEM", namedParameterSpec("ML-KEM-768"), UNSUPPORTED_SIGN),
988 /**
989 * The ML-KEM-1024 algorithm is the NIST FIPS 203 version of the post-quantum Kyber algorithm.
990 * It has 256-bits of classical security strength, and is claimed to meet NIST Level 5
991 * quantum security strength (equivalent to finding the key for an AES-256 block).
992 * <p>
993 * This algorithm was added in Java 24, and may not be supported everywhere.
994 */
995 mlKem1024("ML-KEM", namedParameterSpec("ML-KEM-1024"), UNSUPPORTED_SIGN);
996
997 final String keyType;
998 final AlgorithmParameterSpec parameterSpec;
999 final String signatureType;
1000
1001 Algorithm(String keyType, AlgorithmParameterSpec parameterSpec, String signatureType) {
1002 this.keyType = keyType;
1003 this.parameterSpec = parameterSpec;
1004 this.signatureType = signatureType;
1005 }
1006
1007 private static AlgorithmParameterSpec namedParameterSpec(String name) {
1008 try {
1009 Class<?> cls = Class.forName("java.security.spec.NamedParameterSpec");
1010 return (AlgorithmParameterSpec) cls.getConstructor(String.class).newInstance(name);
1011 } catch (Exception e) {
1012 if ("Ed25519".equals(name)) {
1013 return new EdDSAParameterSpec(EdDSAParameterSpec.Ed25519);
1014 }
1015 if ("Ed448".equals(name)) {
1016 return new EdDSAParameterSpec(EdDSAParameterSpec.Ed448);
1017 }
1018 return UNSUPPORTED_SPEC;
1019 }
1020 }
1021
1022 /**
1023 * Generate a new {@link KeyPair} using this algorithm, and the given {@link SecureRandom} generator.
1024 * @param secureRandom The {@link SecureRandom} generator to use, not {@code null}.
1025 * @return The generated {@link KeyPair}.
1026 * @throws GeneralSecurityException if the key pair cannot be generated using this algorithm for some reason.
1027 * @throws UnsupportedOperationException if this algorithm is not support in the current JVM.
1028 */
1029 public KeyPair generateKeyPair(SecureRandom secureRandom)
1030 throws GeneralSecurityException {
1031 return generateKeyPair(secureRandom, null);
1032 }
1033
1034 /**
1035 * Generate a new {@link KeyPair} using this algorithm, and the given {@link SecureRandom} generator.
1036 * @param secureRandom The {@link SecureRandom} generator to use, not {@code null}.
1037 * @param provider The {@link Provider} to use, when {@code null}, the default will be used.
1038 * @return The generated {@link KeyPair}.
1039 * @throws GeneralSecurityException if the key pair cannot be generated using this algorithm for some reason.
1040 * @throws UnsupportedOperationException if this algorithm is not support in the current JVM.
1041 */
1042 public KeyPair generateKeyPair(SecureRandom secureRandom, Provider provider)
1043 throws GeneralSecurityException {
1044 requireNonNull(secureRandom, "secureRandom");
1045
1046 if (parameterSpec == UNSUPPORTED_SPEC) {
1047 throw new UnsupportedOperationException("This algorithm is not supported: " + this);
1048 }
1049
1050 KeyPairGenerator keyGen = Algorithms.keyPairGenerator(keyType, parameterSpec, secureRandom, provider);
1051 return keyGen.generateKeyPair();
1052 }
1053
1054 /**
1055 * Tell whether this algorithm is supported in the current JVM.
1056 * @return {@code true} if this algorithm is supported.
1057 */
1058 public boolean isSupported() {
1059 return parameterSpec != UNSUPPORTED_SPEC;
1060 }
1061
1062 /**
1063 * Discern if this algorithm can be used for signing.
1064 * Algorithms need to support signing in order to create self-signed certificates,
1065 * or to be used as signing issuers of other certificates.
1066 * <p>
1067 * Note that this method only inspects a property of the algorithm, and does not check if the algorithm
1068 * {@linkplain #isSupported() is supported} in your environment.
1069 *
1070 * @return {@code true} if this algorithm can be used for signing, otherwise {@code false}.
1071 */
1072 public boolean supportSigning() {
1073 return !Objects.equals(signatureType, UNSUPPORTED_SIGN);
1074 }
1075 }
1076
1077 /**
1078 * The key usage field specify what the certificate and key is allowed to be used for.
1079 * <p>
1080 * These key usages are specified by the X.509 standard, and some of them are deprecated.
1081 * <p>
1082 * See the {@link ExtendedKeyUsage} for other commonly used key usage extensions.
1083 * <p>
1084 * See ITU-T X.509 (10/2019) section 9.2.2.3 for the precise meaning of these usages.
1085 */
1086 public enum KeyUsage {
1087 /**
1088 * For verifying digital signatures, for entity authentication,
1089 * for entity authentication, or for integrity verification.
1090 */
1091 digitalSignature(0),
1092 /**
1093 * This key usage is deprecated by X.509, and commitment may instead be derived from the actual use of the keys.
1094 * <p>
1095 * For verifying digital signatures that imply the signer has "committed" to the
1096 * content being signed. This does not imply any specific policy or review on part of the signer, however.
1097 */
1098 contentCommitment(1),
1099 /**
1100 * For enciphering keys or other security information.
1101 */
1102 keyEncipherment(2),
1103 /**
1104 * For enciphering user data, but not keys or security information.
1105 */
1106 dataEncipherment(3),
1107 /**
1108 * For use in public key agreement.
1109 */
1110 keyAgreement(4),
1111 /**
1112 * For verifying the Certificate Authority's signature on a public-key certificate.
1113 * <p>
1114 * This implies {@link #digitalSignature} and {@link #contentCommitment}, so they do not need to be specified
1115 * separately.
1116 */
1117 keyCertSign(5),
1118 /**
1119 * For verifying the Certificate Authority's signature on a Certificate Revocation List.
1120 * <p>
1121 * This implies {@link #digitalSignature} and {@link #contentCommitment}, so they do not need to be specified
1122 * separately.
1123 */
1124 cRLSign(6),
1125 /**
1126 * For use with {@link #keyAgreement} to limit the key to enciphering only.
1127 * <p>
1128 * The meaning of this without the {@link #keyAgreement} bit set is unspecified.
1129 */
1130 encipherOnly(7),
1131 /**
1132 * For use with {@link #keyAgreement} to limit the key to deciphering only.
1133 * <p>
1134 * The meaning of this without the {@link #keyAgreement} bit set is unspecified.
1135 */
1136 decipherOnly(8);
1137
1138 private final int bitId;
1139
1140 KeyUsage(int bitId) {
1141 this.bitId = bitId;
1142 }
1143 }
1144
1145 /**
1146 * The extended key usage field specify what the certificate and key is allowed to be used for.
1147 * <p>
1148 * A certificate can have many key usages. For instance, some certificates support both client and server usage
1149 * for TLS connections.
1150 * <p>
1151 * The key usage must be checked by the opposing peer receiving the certificate, and reject certificates that do
1152 * not permit the given usage.
1153 * <p>
1154 * For instance, if a TLS client connects to a server that presents a certificate without the
1155 * {@linkplain #PKIX_KP_SERVER_AUTH server-authentication} usage, then the client must reject the server
1156 * certificate as invalid.
1157 */
1158 public enum ExtendedKeyUsage {
1159 /**
1160 * The certificate can be used on the server-side of a TLS connection.
1161 */
1162 PKIX_KP_SERVER_AUTH(OID_PKIX_KP_SERVER_AUTH),
1163 /**
1164 * The certificate can be used on the client-side of a TLS connection.
1165 */
1166 PKIX_KP_CLIENT_AUTH(OID_PKIX_KP_CLIENT_AUTH),
1167 /**
1168 * The certificate can be used for code signing.
1169 */
1170 PKIX_KP_CODE_SIGNING(OID_PKIX_KP_CODE_SIGNING),
1171 /**
1172 * The certificate can be used for protecting email.
1173 */
1174 PKIX_KP_EMAIL_PROTECTION(OID_PKIX_KP_EMAIL_PROTECTION),
1175 /**
1176 * The certificate can be used for time-stamping.
1177 */
1178 PKIX_KP_TIME_STAMPING(OID_PKIX_KP_TIME_STAMPING),
1179 /**
1180 * The certificate can be used to sign OCSP replies.
1181 */
1182 PKIX_KP_OCSP_SIGNING(OID_PKIX_KP_OCSP_SIGNING),
1183 /**
1184 * The certificate can be used for Kerberos client authentication.
1185 */
1186 KERBEROS_KEY_PURPOSE_CLIENT_AUTH(OID_KERBEROS_KEY_PURPOSE_CLIENT_AUTH),
1187 /**
1188 * The certificate can be used for Microsoft smartcard logins.
1189 */
1190 MICROSOFT_SMARTCARD_LOGIN(OID_MICROSOFT_SMARTCARD_LOGIN);
1191
1192 private final String oid;
1193
1194 ExtendedKeyUsage(String oid) {
1195 this.oid = oid;
1196 }
1197
1198 public String getOid() {
1199 return oid;
1200 }
1201 }
1202
1203 @FunctionalInterface
1204 private interface BuilderCallback {
1205 void modify(ExtensionsGenerator builder) throws Exception;
1206 }
1207
1208 private static final class SecureRandomHolder {
1209 private static final SecureRandom RANDOM = new SecureRandom();
1210 }
1211 }