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 KeyPair keyPair;
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.keyPair = keyPair;
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 publicKey The public key to wrap in a certificate.
457 * @return This certificate builder.
458 */
459 public CertificateBuilder publicKey(PublicKey publicKey) {
460 if (publicKey == null) {
461 keyPair = null;
462 } else {
463 keyPair = new KeyPair(publicKey, null);
464 }
465 return this;
466 }
467
468 /**
469 * Instruct the certificate builder to not generate its own key pair, but to instead create a certificate that
470 * uses the given key pair.
471 * <p>
472 * This method is useful if you want to use an existing key-pair, e.g. to emulate a certificate authority
473 * responding to a Certificate Signing Request (CSR), or when creating cross-signed certificates.
474 * <p>
475 * Cross-signing is when two certificates have the same subject and public key, but are signed by different keys.
476 * In effect, it's the same logical certificate, but manifest as two different "concrete" certificate objects, i.e.
477 * two different {@link X509Bundle} objects. Cross-signing can be done to both leaf certificates and to issuers,
478 * and can create complicated certificate graphs. The technique is used for introducing new roots and issuers
479 * to a PKI system, in a backwards compatible way where certificates can be trusted by peers that aren't familiar
480 * with the new roots or issuers.
481 * <p>
482 * If the given key pair is {@code null} (the default) then a new key-pair will be generated instead.
483 *
484 * @param keyPair The key pair to use when creating a certificate.
485 * @return This certificate builder.
486 */
487 public CertificateBuilder keyPair(KeyPair keyPair) {
488 if (keyPair != null && keyPair.getPublic() == null) {
489 throw new IllegalArgumentException("The given key pair must have a public key");
490 }
491 this.keyPair = keyPair;
492 return this;
493 }
494
495 private CertificateBuilder addExtension(String identifierOid, boolean critical, byte[] value) {
496 requireNonNull(identifierOid, "identifierOid");
497 requireNonNull(value, "value");
498 modifierCallbacks.add(builder -> {
499 builder.addExtension(new Extension(
500 new ASN1ObjectIdentifier(identifierOid),
501 critical,
502 value));
503 });
504 return this;
505 }
506
507 /**
508 * Add a custom extension to the certificate, with the given OID, criticality flag, and DER-encoded contents.
509 * @param identifierOID The OID identifying the extension.
510 * @param critical {@code true} if the extension is critical, otherwise {@code false}.
511 * Certificate systems MUST reject certificates with critical extensions they don't recognize.
512 * @param contents The DER-encoded extension contents.
513 * @return This certificate builder.
514 */
515 public CertificateBuilder addExtensionOctetString(String identifierOID, boolean critical, byte[] contents) {
516 requireNonNull(identifierOID, "identifierOID");
517 requireNonNull(contents, "contents");
518 modifierCallbacks.add(builder -> {
519 builder.addExtension(new Extension(
520 new ASN1ObjectIdentifier(identifierOID),
521 critical,
522 contents));
523 });
524 return this;
525 }
526
527 /**
528 * Add a custom DER-encoded ASN.1 UTF-8 string extension to the certificate, with the given OID, criticality,
529 * and string value.
530 * The string will be converted to its proper binary encoding by this method.
531 * @param identifierOID The OID identifying the extension.
532 * @param critical {@code true} if the extension is critical, otherwise {@code false}.
533 * Certificate systems MUST reject certificates with critical extensions they don't recognize.
534 * @param value The string value.
535 * @return This certificate builder.
536 */
537 public CertificateBuilder addExtensionUtf8String(String identifierOID, boolean critical, String value) {
538 try {
539 return addExtension(identifierOID, critical, new DERUTF8String(value).getEncoded("DER"));
540 } catch (IOException e) {
541 throw new UncheckedIOException(e);
542 }
543 }
544
545 /**
546 * Add a custom DER-encoded ASN.1 IA5String (an ASCII string) extension to the certificate, with the given OID,
547 * criticality, and string value.
548 * The string will be converted to its proper binary encoding by this method.
549 * @param identifierOID The OID identifying the extension.
550 * @param critical {@code true} if the extension is critical, otherwise {@code false}.
551 * Certificate systems MUST reject certificates with critical extensions they don't recognize.
552 * @param value The string value.
553 * @return This certificate builder.
554 */
555 public CertificateBuilder addExtensionAsciiString(String identifierOID, boolean critical, String value) {
556 try {
557 return addExtension(identifierOID, critical, new DERIA5String(value).getEncoded("DER"));
558 } catch (IOException e) {
559 throw new UncheckedIOException(e);
560 }
561 }
562
563 /**
564 * The key usage specify the intended usages for which the certificate has been issued.
565 * Some are overlapping, some are deprecated, and some are implied by usage.
566 * <p>
567 * For Certificate Authority usage, the important ones are {@link KeyUsage#keyCertSign}
568 * and {@link KeyUsage#cRLSign}.
569 * <p>
570 * Any certificate that has {@link KeyUsage#keyCertSign} must also have {@link #setIsCertificateAuthority(boolean)}
571 * set to {@code true}.
572 *
573 * @param critical {@code true} if certificate recipients are required to understand all the set bits,
574 * otherwise {@code false}.
575 * @param keyUsages The key usages to set.
576 * @return This certificate builder.
577 */
578 public CertificateBuilder setKeyUsage(boolean critical, KeyUsage... keyUsages) {
579 int maxBit = 0;
580 for (KeyUsage usage : keyUsages) {
581 maxBit = Math.max(usage.bitId, maxBit);
582 }
583 boolean[] bits = new boolean[maxBit + 1];
584 for (KeyUsage usage : keyUsages) {
585 bits[usage.bitId] = true;
586 }
587 int padding = 8 - bits.length % 8;
588 int lenBytes = bits.length / 8 + 1;
589 if (padding == 8) {
590 padding = 0;
591 lenBytes--;
592 }
593 byte[] bytes = new byte[lenBytes];
594 for (int i = 0; i < bits.length; i++) {
595 if (bits[i]) {
596 int byteIndex = i / 8;
597 int bitIndex = i % 8;
598 bytes[byteIndex] |= (byte) (0x80 >>> bitIndex);
599 }
600 }
601
602 try {
603 keyUsage = new Extension(
604 Extension.keyUsage,
605 critical,
606 new DERBitString(bytes, padding).getEncoded("DER"));
607 } catch (IOException e) {
608 throw new UncheckedIOException(e);
609 }
610 return this;
611 }
612
613 /**
614 * Add the given OID to the list of extended key usages.
615 * @param oid The OID to add.
616 * @return This certificate builder.
617 * @see ExtendedKeyUsage
618 * @see #addExtendedKeyUsage(ExtendedKeyUsage)
619 */
620 public CertificateBuilder addExtendedKeyUsage(String oid) {
621 extendedKeyUsage.add(oid);
622 return this;
623 }
624
625 /**
626 * Add the given {@link ExtendedKeyUsage} to the list of extended key usages.
627 * @param keyUsage The extended key usage to add.
628 * @return This certificate builder.
629 */
630 public CertificateBuilder addExtendedKeyUsage(ExtendedKeyUsage keyUsage) {
631 extendedKeyUsage.add(keyUsage.getOid());
632 return this;
633 }
634
635 /**
636 * Add server-authentication to the list of extended key usages.
637 * @return This certificate builder.
638 */
639 public CertificateBuilder addExtendedKeyUsageServerAuth() {
640 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_SERVER_AUTH);
641 }
642
643 /**
644 * Add client-authentication to the list of extended key usages.
645 * @return This certificate builder.
646 */
647 public CertificateBuilder addExtendedKeyUsageClientAuth() {
648 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_CLIENT_AUTH);
649 }
650
651 /**
652 * Add code signing to the list of extended key usages.
653 * @return This certificate builder.
654 */
655 public CertificateBuilder addExtendedKeyUsageCodeSigning() {
656 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_CODE_SIGNING);
657 }
658
659 /**
660 * Add email protection to the list of extended key usages.
661 * @return This certificate builder.
662 */
663 public CertificateBuilder addExtendedKeyUsageEmailProtection() {
664 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_EMAIL_PROTECTION);
665 }
666
667 /**
668 * Add time-stamping to the list of extended key usages.
669 * @return This certificate builder.
670 */
671 public CertificateBuilder addExtendedKeyUsageTimeStamping() {
672 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_TIME_STAMPING);
673 }
674
675 /**
676 * Add OCSP signing to the list of extended key usages.
677 * @return This certificate builder.
678 */
679 public CertificateBuilder addExtendedKeyUsageOcspSigning() {
680 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_OCSP_SIGNING);
681 }
682
683 /**
684 * Add Kerberos client authentication to the list of extended key usages.
685 * @return This certificate builder.
686 */
687 public CertificateBuilder addExtendedKeyUsageKerberosClientAuth() {
688 return addExtendedKeyUsage(ExtendedKeyUsage.KERBEROS_KEY_PURPOSE_CLIENT_AUTH);
689 }
690
691 /**
692 * Add Microsoft smartcard login to the list of extended key usages.
693 * @return This certificate builder.
694 */
695 public CertificateBuilder addExtendedKeyUsageMicrosoftSmartcardLogin() {
696 return addExtendedKeyUsage(ExtendedKeyUsage.MICROSOFT_SMARTCARD_LOGIN);
697 }
698
699 /**
700 * Build a {@link X509Bundle} with a self-signed certificate.
701 * @return The newly created bundle.
702 * @throws Exception If something went wrong in the process.
703 */
704 public X509Bundle buildSelfSigned() throws Exception {
705 if (keyPair != null && (keyPair.getPublic() == null || keyPair.getPrivate() == null)) {
706 throw new IllegalStateException("Cannot create a self-signed certificate with an incomplete key pair.");
707 }
708 if (!algorithm.supportSigning()) {
709 throw new IllegalStateException("Cannot create a self-signed certificate with a " +
710 "key algorithm that does not support signing: " + algorithm);
711 }
712 KeyPair keyPair = generateKeyPair(provider);
713
714 V3TBSCertificateGenerator generator = createCertBuilder(subject, subject, keyPair, algorithm.signatureType);
715
716 addExtensions(generator);
717
718 Signed signed = new Signed(tbsCertToBytes(generator), algorithm.signatureType, keyPair.getPrivate());
719 CertificateFactory factory = CertificateFactory.getInstance("X.509");
720 X509Certificate cert = (X509Certificate) factory.generateCertificate(signed.toInputStream(provider));
721 return X509Bundle.fromRootCertificateAuthority(cert, keyPair);
722 }
723
724 /**
725 * Build a {@link X509Bundle} with a certificate signed by the given issuer bundle.
726 * The signing algorithm used will be derived from the issuers public key.
727 * @return The newly created bundle.
728 * @throws Exception If something went wrong in the process.
729 */
730 public X509Bundle buildIssuedBy(X509Bundle issuerBundle) throws Exception {
731 String issuerSignAlgorithm = preferredSignatureAlgorithm(issuerBundle.getCertificate().getPublicKey());
732 return buildIssuedBy(issuerBundle, issuerSignAlgorithm);
733 }
734
735 /**
736 * Build a {@link X509Bundle} with a certificate signed by the given issuer bundle, using the specified
737 * signing algorithm.
738 * @return The newly created bundle.
739 * @throws Exception If something went wrong in the process.
740 */
741 public X509Bundle buildIssuedBy(X509Bundle issuerBundle, String signAlg) throws Exception {
742 final KeyPair keyPair;
743 if (this.keyPair == null) {
744 keyPair = generateKeyPair(provider);
745 } else {
746 keyPair = this.keyPair;
747 }
748
749 X500Principal issuerPrincipal = issuerBundle.getCertificate().getSubjectX500Principal();
750 V3TBSCertificateGenerator generator = createCertBuilder(issuerPrincipal, subject, keyPair, signAlg);
751
752 addExtensions(generator);
753
754 PrivateKey issuerPrivateKey = issuerBundle.getKeyPair().getPrivate();
755 if (issuerPrivateKey == null) {
756 throw new IllegalArgumentException(
757 "Cannot sign certificate with issuer bundle that does not have a private key.");
758 }
759 Signed signed = new Signed(tbsCertToBytes(generator), signAlg, issuerPrivateKey);
760 CertificateFactory factory = CertificateFactory.getInstance("X.509");
761 X509Certificate cert = (X509Certificate) factory.generateCertificate(signed.toInputStream(provider));
762 X509Certificate[] issuerPath = issuerBundle.getCertificatePath();
763 X509Certificate[] path = new X509Certificate[issuerPath.length + 1];
764 path[0] = cert;
765 System.arraycopy(issuerPath, 0, path, 1, issuerPath.length);
766 return X509Bundle.fromCertificatePath(path, issuerBundle.getRootCertificate(), keyPair);
767 }
768
769 private static String preferredSignatureAlgorithm(PublicKey key) {
770 if (key instanceof RSAPublicKey) {
771 RSAPublicKey rsa = (RSAPublicKey) key;
772 if (rsa.getModulus().bitLength() < 4096) {
773 return "SHA256withRSA";
774 }
775 return "SHA384withRSA";
776 }
777 if (key instanceof ECPublicKey) {
778 ECPublicKey ec = (ECPublicKey) key;
779 int size = ec.getW().getAffineX().bitLength();
780 // Note: the coords are not guaranteed to use up all available bits, hence less-than-or-equal checks.
781 if (size <= 256) {
782 return "SHA256withECDSA";
783 }
784 if (size <= 384) {
785 return "SHA384withECDSA";
786 }
787 return "SHA512withECDSA";
788 }
789 if (key instanceof DSAPublicKey) {
790 throw new IllegalArgumentException("DSA keys are not supported because they are obsolete");
791 }
792 String keyAlgorithm = key.getAlgorithm();
793 if ("Ed25519".equals(keyAlgorithm) || "1.3.101.112".equals(keyAlgorithm)) {
794 return "Ed25519";
795 }
796 if ("Ed448".equals(keyAlgorithm) || "1.3.101.113".equals(keyAlgorithm)) {
797 return "Ed448";
798 }
799 if ("EdDSA".equals(keyAlgorithm)) {
800 byte[] encoded = key.getEncoded();
801 if (encoded.length <= 44) {
802 return "Ed25519";
803 }
804 if (encoded.length <= 69) {
805 return "Ed448";
806 }
807 }
808 if ("ML-DSA".equals(keyAlgorithm)) {
809 try {
810 Method getParams = Class.forName("java.security.AsymmetricKey").getMethod("getParams");
811 Object params = getParams.invoke(key);
812 Method getName = params.getClass().getMethod("getName");
813 return (String) getName.invoke(params);
814 } catch (Exception e) {
815 throw new IllegalArgumentException("Cannot get algorithm name for ML-DSA key", e);
816 }
817 }
818 if ("ML-KEM".equals(keyAlgorithm)) {
819 throw new IllegalArgumentException("ML-KEM keys cannot be used for signing");
820 }
821 throw new IllegalArgumentException("Don't know what signature algorithm is best for " + key);
822 }
823
824 private KeyPair generateKeyPair(Provider provider) throws GeneralSecurityException {
825 return algorithm.generateKeyPair(getSecureRandom(), provider);
826 }
827
828 private V3TBSCertificateGenerator createCertBuilder(
829 X500Principal issuer, X500Principal subject, KeyPair keyPair, String signAlg) {
830 BigInteger serial = this.serial != null ? this.serial : new BigInteger(159, getSecureRandom());
831 PublicKey pubKey = keyPair.getPublic();
832
833 V3TBSCertificateGenerator generator = new V3TBSCertificateGenerator();
834 generator.setIssuer(X500Name.getInstance(issuer.getEncoded()));
835 if (subject != null) {
836 generator.setSubject(X500Name.getInstance(subject.getEncoded()));
837 }
838 generator.setSerialNumber(new ASN1Integer(serial));
839 generator.setSignature(new AlgorithmIdentifier(new ASN1ObjectIdentifier(
840 Algorithms.oidForAlgorithmName(signAlg))));
841 generator.setStartDate(new Time(Date.from(notBefore)));
842 generator.setEndDate(new Time(Date.from(notAfter)));
843 generator.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()));
844 return generator;
845 }
846
847 private static byte[] tbsCertToBytes(V3TBSCertificateGenerator generator) {
848 try {
849 return generator.generateTBSCertificate().getEncoded("DER");
850 } catch (IOException e) {
851 throw new UncheckedIOException(e);
852 }
853 }
854
855 private SecureRandom getSecureRandom() {
856 SecureRandom rng = random;
857 if (rng == null) {
858 rng = SecureRandomHolder.RANDOM;
859 }
860 return rng;
861 }
862
863 private void addExtensions(V3TBSCertificateGenerator tbsCert) throws Exception {
864 ExtensionsGenerator generator = new ExtensionsGenerator();
865 if (isCertificateAuthority) {
866 final BasicConstraints basicConstraints;
867 if (pathLengthConstraint.isPresent()) {
868 basicConstraints = new BasicConstraints(pathLengthConstraint.getAsInt());
869 } else {
870 basicConstraints = new BasicConstraints(true);
871 }
872 final byte[] basicConstraintsBytes = basicConstraints.getEncoded("DER");
873 generator.addExtension(new Extension(Extension.basicConstraints, true, basicConstraintsBytes));
874 }
875 if (keyUsage != null) {
876 generator.addExtension(keyUsage);
877 }
878
879 if (!extendedKeyUsage.isEmpty()) {
880 KeyPurposeId[] usages = new KeyPurposeId[extendedKeyUsage.size()];
881 String[] usagesStrings = extendedKeyUsage.toArray(EmptyArrays.EMPTY_STRINGS);
882 for (int i = 0; i < usagesStrings.length; i++) {
883 usages[i] = KeyPurposeId.getInstance(new ASN1ObjectIdentifier(usagesStrings[i]));
884 }
885 byte[] der = new org.bouncycastle.asn1.x509.ExtendedKeyUsage(usages).getEncoded("DER");
886 generator.addExtension(new Extension(Extension.extendedKeyUsage, false, der));
887 }
888
889 if (!subjectAlternativeNames.isEmpty()) {
890 // SAN is critical extension if subject is empty sequence:
891 boolean critical = subject.getName().isEmpty();
892 byte[] result;
893 GeneralNames generalNames = new GeneralNames(subjectAlternativeNames.toArray(EMPTY_GENERAL_NAMES));
894 try {
895 result = generalNames.getEncoded("DER");
896 } catch (IOException e) {
897 throw new UncheckedIOException(e);
898 }
899 generator.addExtension(new Extension(Extension.subjectAlternativeName, critical, result));
900 }
901
902 if (!crlDistributionPoints.isEmpty()) {
903 generator.addExtension(Extension.create(
904 Extension.cRLDistributionPoints,
905 false,
906 new CRLDistPoint(crlDistributionPoints.toArray(EMPTY_DIST_POINTS))));
907 }
908
909 for (BuilderCallback callback : modifierCallbacks) {
910 callback.modify(generator);
911 }
912
913 if (!generator.isEmpty()) {
914 tbsCert.setExtensions(generator.generate());
915 }
916 }
917
918 /**
919 * The {@link Algorithm} enum encapsulates both the key type, key generation parameters, and the signature
920 * algorithm to use.
921 */
922 public enum Algorithm {
923 /**
924 * The NIST P-256 elliptic curve algorithm, offer fast key generation, signing, and verification,
925 * with small keys and signatures, at 128-bits of security strength.
926 * <p>
927 * This algorithm is older than the Edwards curves, and are more widely supported.
928 */
929 ecp256("EC", new ECGenParameterSpec("secp256r1"), "SHA256withECDSA"),
930 /**
931 * The NIST P-384 elliptic curve algorithm, offer fast key generation, signing, and verification,
932 * with small keys and signatures, at 192-bits of security strength.
933 * <p>
934 * This algorithm is older than the Edwards curves, and are more widely supported.
935 */
936 ecp384("EC", new ECGenParameterSpec("secp384r1"), "SHA384withECDSA"),
937 /**
938 * The 2048-bit RSA algorithm offer roughly 112-bits of security strength, at the cost of large keys
939 * and slightly expensive key generation.
940 * <p>
941 * This algorithm enjoy the widest support and compatibility, though.
942 */
943 rsa2048("RSA", new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4), "SHA256withRSA"),
944 /**
945 * The 3072-bit RSA algorithm offer roughly 128-bits of security strength, at the cost of large keys
946 * and fairly expensive key generation.
947 * <p>
948 * RSA enjoy pretty wide compatibility, though not all systems support keys this large.
949 */
950 rsa3072("RSA", new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4), "SHA256withRSA"),
951 /**
952 * The 4096-bit RSA algorithm offer roughly greater than 128-bits of security strength,
953 * at the cost of large keys and very expensive key generation.
954 * <p>
955 * RSA enjoy pretty wide compatibility, though not all systems support keys this large.
956 */
957 rsa4096("RSA", new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4), "SHA384withRSA"),
958 /**
959 * The 8192-bit RSA algorithm offer roughly greater than 192-bits of security strength,
960 * at the cost of very large keys and extremely expensive key generation.
961 * <p>
962 * RSA enjoy pretty wide compatibility, though not all systems support keys this large.
963 */
964 rsa8192("RSA", new RSAKeyGenParameterSpec(8192, RSAKeyGenParameterSpec.F4), "SHA384withRSA"),
965 /**
966 * The Ed25519 algorithm offer fast key generation, signing, and verification,
967 * with very small keys and signatures, at 128-bits of security strength.
968 * <p>
969 * This algorithm was added in Java 15, and may not be supported everywhere.
970 */
971 ed25519("Ed25519", namedParameterSpec("Ed25519"), "Ed25519"),
972 /**
973 * The Ed448 algorithm offer fast key generation, signing, and verification,
974 * with small keys and signatures, at 224-bits of security strength.
975 * <p>
976 * This algorithm was added in Java 15, and may not be supported everywhere.
977 */
978 ed448("Ed448", namedParameterSpec("Ed448"), "Ed448"),
979 /**
980 * The ML-DSA-44 algorithm is the NIST FIPS 204 version of the post-quantum Dilithium algorithm.
981 * It has 128-bits of classical security strength, and is claimed to meet NIST Level 2
982 * quantum security strength (equivalent to finding a SHA-256 collision).
983 * <p>
984 * This algorithm was added in Java 24, and may not be supported everywhere.
985 */
986 mlDsa44("ML-DSA", namedParameterSpec("ML-DSA-44"), "ML-DSA-44"),
987 /**
988 * The ML-DSA-65 algorithm is the NIST FIPS 204 version of the post-quantum Dilithium algorithm.
989 * It has 192-bits of classical security strength, and is claimed to meet NIST Level 3
990 * quantum security strength (equivalent to finding the key for an AES-192 block).
991 * <p>
992 * This algorithm was added in Java 24, and may not be supported everywhere.
993 */
994 mlDsa65("ML-DSA", namedParameterSpec("ML-DSA-65"), "ML-DSA-65"),
995 /**
996 * The ML-DSA-87 algorithm is the NIST FIPS 204 version of the post-quantum Dilithium algorithm.
997 * It has 256-bits of classical security strength, and is claimed to meet NIST Level 5
998 * quantum security strength (equivalent to finding the key for an AES-256 block).
999 * <p>
1000 * This algorithm was added in Java 24, and may not be supported everywhere.
1001 */
1002 mlDsa87("ML-DSA", namedParameterSpec("ML-DSA-87"), "ML-DSA-87"),
1003 /**
1004 * The ML-KEM-512 algorithm is the NIST FIPS 203 version of the post-quantum Kyber algorithm.
1005 * It has 128-bits of classical security strength, and is claimed to meet NIST Level 1
1006 * quantum security strength (equivalent to finding the key for an AES-128 block).
1007 * <p>
1008 * This algorithm was added in Java 24, and may not be supported everywhere.
1009 */
1010 mlKem512("ML-KEM", namedParameterSpec("ML-KEM-512"), UNSUPPORTED_SIGN),
1011 /**
1012 * The ML-KEM-768 algorithm is the NIST FIPS 203 version of the post-quantum Kyber algorithm.
1013 * It has 192-bits of classical security strength, and is claimed to meet NIST Level 3
1014 * quantum security strength (equivalent to finding the key for an AES-192 block).
1015 * <p>
1016 * This algorithm was added in Java 24, and may not be supported everywhere.
1017 */
1018 mlKem768("ML-KEM", namedParameterSpec("ML-KEM-768"), UNSUPPORTED_SIGN),
1019 /**
1020 * The ML-KEM-1024 algorithm is the NIST FIPS 203 version of the post-quantum Kyber algorithm.
1021 * It has 256-bits of classical security strength, and is claimed to meet NIST Level 5
1022 * quantum security strength (equivalent to finding the key for an AES-256 block).
1023 * <p>
1024 * This algorithm was added in Java 24, and may not be supported everywhere.
1025 */
1026 mlKem1024("ML-KEM", namedParameterSpec("ML-KEM-1024"), UNSUPPORTED_SIGN),
1027 /**
1028 * The SLH-DSA-SHA2-128s algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1029 * It has 128-bits of classical security strength, and is claimed to meet NIST Level 1
1030 * quantum security strength (equivalent to finding the key for an AES-128 block).
1031 * <p>
1032 * SLH-DSA algorithms with the 's' suffix have relatively smaller signatures but are much slower.
1033 */
1034 slhDsaSha2_128s("SLH-DSA", namedParameterSpec("SLH-DSA-SHA2-128s"), "SLH-DSA-SHA2-128s"),
1035 /**
1036 * The SLH-DSA-SHA2-128f algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1037 * It has 128-bits of classical security strength, and is claimed to meet NIST Level 1
1038 * quantum security strength (equivalent to finding the key for an AES-128 block).
1039 * <p>
1040 * SLH-DSA algorithms with the 'f' suffix have larger signatures but are much faster.
1041 */
1042 slhDsaSha2_128f("SLH-DSA", namedParameterSpec("SLH-DSA-SHA2-128f"), "SLH-DSA-SHA2-128f"),
1043 /**
1044 * The SLH-DSA-SHAKE-128s algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1045 * It has 128-bits of classical security strength, and is claimed to meet NIST Level 1
1046 * quantum security strength (equivalent to finding the key for an AES-128 block).
1047 * <p>
1048 * SLH-DSA algorithms with the 's' suffix have relatively smaller signatures but are much slower.
1049 */
1050 slhDsaShake_128s("SLH-DSA", namedParameterSpec("SLH-DSA-SHAKE-128s"), "SLH-DSA-SHAKE-128s"),
1051 /**
1052 * The SLH-DSA-SHAKE-128f algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1053 * It has 128-bits of classical security strength, and is claimed to meet NIST Level 1
1054 * quantum security strength (equivalent to finding the key for an AES-128 block).
1055 * <p>
1056 * SLH-DSA algorithms with the 'f' suffix have larger signatures but are much faster.
1057 */
1058 slhDsaShake_128f("SLH-DSA", namedParameterSpec("SLH-DSA-SHAKE-128f"), "SLH-DSA-SHAKE-128f"),
1059 /**
1060 * The SLH-DSA-SHA2-192 algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1061 * It has 192-bits of classical security strength, and is claimed to meet NIST Level 3
1062 * quantum security strength (equivalent to finding the key for an AES-192 block).
1063 * <p>
1064 * SLH-DSA algorithms with the 's' suffix have relatively smaller signatures but are much slower.
1065 */
1066 slhDsaSha2_192s("SLH-DSA", namedParameterSpec("SLH-DSA-SHA2-192s"), "SLH-DSA-SHA2-192s"),
1067 /**
1068 * The SLH-DSA-SHA2-192f algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1069 * It has 192-bits of classical security strength, and is claimed to meet NIST Level 3
1070 * quantum security strength (equivalent to finding the key for an AES-192 block).
1071 * <p>
1072 * SLH-DSA algorithms with the 'f' suffix have larger signatures but are much faster.
1073 */
1074 slhDsaSha2_192f("SLH-DSA", namedParameterSpec("SLH-DSA-SHA2-192f"), "SLH-DSA-SHA2-192f"),
1075 /**
1076 * The SLH-DSA-SHAKE-192s algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1077 * It has 192-bits of classical security strength, and is claimed to meet NIST Level 3
1078 * quantum security strength (equivalent to finding the key for an AES-192 block).
1079 * <p>
1080 * SLH-DSA algorithms with the 's' suffix have relatively smaller signatures but are much slower.
1081 */
1082 slhDsaShake_192s("SLH-DSA", namedParameterSpec("SLH-DSA-SHAKE-192s"), "SLH-DSA-SHAKE-192s"),
1083 /**
1084 * The SLH-DSA-SHAKE-192f algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1085 * It has 192-bits of classical security strength, and is claimed to meet NIST Level 3
1086 * quantum security strength (equivalent to finding the key for an AES-192 block).
1087 * <p>
1088 * SLH-DSA algorithms with the 'f' suffix have larger signatures but are much faster.
1089 */
1090 slhDsaShake_192f("SLH-DSA", namedParameterSpec("SLH-DSA-SHAKE-192f"), "SLH-DSA-SHAKE-192f"),
1091 /**
1092 * The SLH-DSA-SHA2-256s algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1093 * It has 256-bits of classical security strength, and is claimed to meet NIST Level 5
1094 * quantum security strength (equivalent to finding the key for an AES-256 block).
1095 * <p>
1096 * SLH-DSA algorithms with the 's' suffix have relatively smaller signatures but are much slower.
1097 */
1098 slhDsaSha2_256s("SLH-DSA", namedParameterSpec("SLH-DSA-SHA2-256s"), "SLH-DSA-SHA2-256s"),
1099 /**
1100 * The SLH-DSA-SHA2-256f algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1101 * It has 256-bits of classical security strength, and is claimed to meet NIST Level 5
1102 * quantum security strength (equivalent to finding the key for an AES-256 block).
1103 * <p>
1104 * SLH-DSA algorithms with the 'f' suffix have larger signatures but are much faster.
1105 */
1106 slhDsaSha2_256f("SLH-DSA", namedParameterSpec("SLH-DSA-SHA2-256f"), "SLH-DSA-SHA2-256f"),
1107 /**
1108 * The SLH-DSA-SHAKE-256s algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1109 * It has 256-bits of classical security strength, and is claimed to meet NIST Level 5
1110 * quantum security strength (equivalent to finding the key for an AES-256 block).
1111 * <p>
1112 * SLH-DSA algorithms with the 's' suffix have relatively smaller signatures but are much slower.
1113 */
1114 slhDsaShake_256s("SLH-DSA", namedParameterSpec("SLH-DSA-SHAKE-256s"), "SLH-DSA-SHAKE-256s"),
1115 /**
1116 * The SLH-DSA-SHAKE-256f algorithm is the NIST FIPS 205 of the post-quantum SPHINCS+ algorithm.
1117 * It has 256-bits of classical security strength, and is claimed to meet NIST Level 5
1118 * quantum security strength (equivalent to finding the key for an AES-256 block).
1119 * <p>
1120 * SLH-DSA algorithms with the 'f' suffix have larger signatures but are much faster.
1121 */
1122 slhDsaShake_256f("SLH-DSA", namedParameterSpec("SLH-DSA-SHAKE-256f"), "SLH-DSA-SHAKE-256f"),
1123 ;
1124
1125 final String keyType;
1126 final AlgorithmParameterSpec parameterSpec;
1127 final String signatureType;
1128
1129 Algorithm(String keyType, AlgorithmParameterSpec parameterSpec, String signatureType) {
1130 this.keyType = keyType;
1131 this.parameterSpec = parameterSpec;
1132 this.signatureType = signatureType;
1133 }
1134
1135 private static AlgorithmParameterSpec namedParameterSpec(String name) {
1136 try {
1137 Class<?> cls = Class.forName("java.security.spec.NamedParameterSpec");
1138 return (AlgorithmParameterSpec) cls.getConstructor(String.class).newInstance(name);
1139 } catch (Exception e) {
1140 if ("Ed25519".equals(name)) {
1141 return new EdDSAParameterSpec(EdDSAParameterSpec.Ed25519);
1142 }
1143 if ("Ed448".equals(name)) {
1144 return new EdDSAParameterSpec(EdDSAParameterSpec.Ed448);
1145 }
1146 return UNSUPPORTED_SPEC;
1147 }
1148 }
1149
1150 /**
1151 * Generate a new {@link KeyPair} using this algorithm, and the given {@link SecureRandom} generator.
1152 * @param secureRandom The {@link SecureRandom} generator to use, not {@code null}.
1153 * @return The generated {@link KeyPair}.
1154 * @throws GeneralSecurityException if the key pair cannot be generated using this algorithm for some reason.
1155 * @throws UnsupportedOperationException if this algorithm is not support in the current JVM.
1156 */
1157 public KeyPair generateKeyPair(SecureRandom secureRandom)
1158 throws GeneralSecurityException {
1159 return generateKeyPair(secureRandom, null);
1160 }
1161
1162 /**
1163 * Generate a new {@link KeyPair} using this algorithm, and the given {@link SecureRandom} generator.
1164 * @param secureRandom The {@link SecureRandom} generator to use, not {@code null}.
1165 * @param provider The {@link Provider} to use, when {@code null}, the default will be used.
1166 * @return The generated {@link KeyPair}.
1167 * @throws GeneralSecurityException if the key pair cannot be generated using this algorithm for some reason.
1168 * @throws UnsupportedOperationException if this algorithm is not support in the current JVM.
1169 */
1170 public KeyPair generateKeyPair(SecureRandom secureRandom, Provider provider)
1171 throws GeneralSecurityException {
1172 requireNonNull(secureRandom, "secureRandom");
1173
1174 if (parameterSpec == UNSUPPORTED_SPEC) {
1175 throw new UnsupportedOperationException("This algorithm is not supported: " + this);
1176 }
1177
1178 KeyPairGenerator keyGen = Algorithms.keyPairGenerator(keyType, parameterSpec, secureRandom, provider);
1179 return keyGen.generateKeyPair();
1180 }
1181
1182 /**
1183 * Tell whether this algorithm is supported in the current JVM.
1184 * @return {@code true} if this algorithm is supported.
1185 */
1186 public boolean isSupported() {
1187 return parameterSpec != UNSUPPORTED_SPEC;
1188 }
1189
1190 /**
1191 * Discern if this algorithm can be used for signing.
1192 * Algorithms need to support signing in order to create self-signed certificates,
1193 * or to be used as signing issuers of other certificates.
1194 * <p>
1195 * Note that this method only inspects a property of the algorithm, and does not check if the algorithm
1196 * {@linkplain #isSupported() is supported} in your environment.
1197 *
1198 * @return {@code true} if this algorithm can be used for signing, otherwise {@code false}.
1199 */
1200 public boolean supportSigning() {
1201 return !Objects.equals(signatureType, UNSUPPORTED_SIGN);
1202 }
1203 }
1204
1205 /**
1206 * The key usage field specify what the certificate and key is allowed to be used for.
1207 * <p>
1208 * These key usages are specified by the X.509 standard, and some of them are deprecated.
1209 * <p>
1210 * See the {@link ExtendedKeyUsage} for other commonly used key usage extensions.
1211 * <p>
1212 * See ITU-T X.509 (10/2019) section 9.2.2.3 for the precise meaning of these usages.
1213 */
1214 public enum KeyUsage {
1215 /**
1216 * For verifying digital signatures, for entity authentication,
1217 * for entity authentication, or for integrity verification.
1218 */
1219 digitalSignature(0),
1220 /**
1221 * This key usage is deprecated by X.509, and commitment may instead be derived from the actual use of the keys.
1222 * <p>
1223 * For verifying digital signatures that imply the signer has "committed" to the
1224 * content being signed. This does not imply any specific policy or review on part of the signer, however.
1225 */
1226 contentCommitment(1),
1227 /**
1228 * For enciphering keys or other security information.
1229 */
1230 keyEncipherment(2),
1231 /**
1232 * For enciphering user data, but not keys or security information.
1233 */
1234 dataEncipherment(3),
1235 /**
1236 * For use in public key agreement.
1237 */
1238 keyAgreement(4),
1239 /**
1240 * For verifying the Certificate Authority's signature on a public-key certificate.
1241 * <p>
1242 * This implies {@link #digitalSignature} and {@link #contentCommitment}, so they do not need to be specified
1243 * separately.
1244 */
1245 keyCertSign(5),
1246 /**
1247 * For verifying the Certificate Authority's signature on a Certificate Revocation List.
1248 * <p>
1249 * This implies {@link #digitalSignature} and {@link #contentCommitment}, so they do not need to be specified
1250 * separately.
1251 */
1252 cRLSign(6),
1253 /**
1254 * For use with {@link #keyAgreement} to limit the key to enciphering only.
1255 * <p>
1256 * The meaning of this without the {@link #keyAgreement} bit set is unspecified.
1257 */
1258 encipherOnly(7),
1259 /**
1260 * For use with {@link #keyAgreement} to limit the key to deciphering only.
1261 * <p>
1262 * The meaning of this without the {@link #keyAgreement} bit set is unspecified.
1263 */
1264 decipherOnly(8);
1265
1266 private final int bitId;
1267
1268 KeyUsage(int bitId) {
1269 this.bitId = bitId;
1270 }
1271 }
1272
1273 /**
1274 * The extended key usage field specify what the certificate and key is allowed to be used for.
1275 * <p>
1276 * A certificate can have many key usages. For instance, some certificates support both client and server usage
1277 * for TLS connections.
1278 * <p>
1279 * The key usage must be checked by the opposing peer receiving the certificate, and reject certificates that do
1280 * not permit the given usage.
1281 * <p>
1282 * For instance, if a TLS client connects to a server that presents a certificate without the
1283 * {@linkplain #PKIX_KP_SERVER_AUTH server-authentication} usage, then the client must reject the server
1284 * certificate as invalid.
1285 */
1286 public enum ExtendedKeyUsage {
1287 /**
1288 * The certificate can be used on the server-side of a TLS connection.
1289 */
1290 PKIX_KP_SERVER_AUTH(OID_PKIX_KP_SERVER_AUTH),
1291 /**
1292 * The certificate can be used on the client-side of a TLS connection.
1293 */
1294 PKIX_KP_CLIENT_AUTH(OID_PKIX_KP_CLIENT_AUTH),
1295 /**
1296 * The certificate can be used for code signing.
1297 */
1298 PKIX_KP_CODE_SIGNING(OID_PKIX_KP_CODE_SIGNING),
1299 /**
1300 * The certificate can be used for protecting email.
1301 */
1302 PKIX_KP_EMAIL_PROTECTION(OID_PKIX_KP_EMAIL_PROTECTION),
1303 /**
1304 * The certificate can be used for time-stamping.
1305 */
1306 PKIX_KP_TIME_STAMPING(OID_PKIX_KP_TIME_STAMPING),
1307 /**
1308 * The certificate can be used to sign OCSP replies.
1309 */
1310 PKIX_KP_OCSP_SIGNING(OID_PKIX_KP_OCSP_SIGNING),
1311 /**
1312 * The certificate can be used for Kerberos client authentication.
1313 */
1314 KERBEROS_KEY_PURPOSE_CLIENT_AUTH(OID_KERBEROS_KEY_PURPOSE_CLIENT_AUTH),
1315 /**
1316 * The certificate can be used for Microsoft smartcard logins.
1317 */
1318 MICROSOFT_SMARTCARD_LOGIN(OID_MICROSOFT_SMARTCARD_LOGIN);
1319
1320 private final String oid;
1321
1322 ExtendedKeyUsage(String oid) {
1323 this.oid = oid;
1324 }
1325
1326 public String getOid() {
1327 return oid;
1328 }
1329 }
1330
1331 @FunctionalInterface
1332 private interface BuilderCallback {
1333 void modify(ExtensionsGenerator builder) throws Exception;
1334 }
1335
1336 private static final class SecureRandomHolder {
1337 private static final SecureRandom RANDOM = new SecureRandom();
1338 }
1339 }