1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.math.BigInteger;
43 import java.net.InetAddress;
44 import java.net.URI;
45 import java.net.URISyntaxException;
46 import java.security.GeneralSecurityException;
47 import java.security.KeyPair;
48 import java.security.KeyPairGenerator;
49 import java.security.PrivateKey;
50 import java.security.PublicKey;
51 import java.security.SecureRandom;
52 import java.security.cert.CertificateFactory;
53 import java.security.cert.X509Certificate;
54 import java.security.interfaces.DSAPublicKey;
55 import java.security.interfaces.ECPublicKey;
56 import java.security.interfaces.RSAPublicKey;
57 import java.security.spec.AlgorithmParameterSpec;
58 import java.security.spec.ECGenParameterSpec;
59 import java.security.spec.RSAKeyGenParameterSpec;
60 import java.time.Instant;
61 import java.time.temporal.ChronoUnit;
62 import java.util.ArrayList;
63 import java.util.Date;
64 import java.util.List;
65 import java.util.OptionalInt;
66 import java.util.Set;
67 import java.util.TreeSet;
68 import javax.security.auth.x500.X500Principal;
69
70 import static java.util.Objects.requireNonNull;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 public final class CertificateBuilder {
104
105 static final String OID_X509_NAME_CONSTRAINTS = "2.5.29.30";
106 static final String OID_PKIX_KP = "1.3.6.1.5.5.7.3";
107 static final String OID_PKIX_KP_SERVER_AUTH = OID_PKIX_KP + ".1";
108 static final String OID_PKIX_KP_CLIENT_AUTH = OID_PKIX_KP + ".2";
109 static final String OID_PKIX_KP_CODE_SIGNING = OID_PKIX_KP + ".3";
110 static final String OID_PKIX_KP_EMAIL_PROTECTION = OID_PKIX_KP + ".4";
111 static final String OID_PKIX_KP_TIME_STAMPING = OID_PKIX_KP + ".8";
112 static final String OID_PKIX_KP_OCSP_SIGNING = OID_PKIX_KP + ".9";
113 static final String OID_KERBEROS_KEY_PURPOSE_CLIENT_AUTH = "1.3.6.1.5.2.3.4";
114 static final String OID_MICROSOFT_SMARTCARD_LOGIN = "1.3.6.1.4.1.311.20.2.2";
115 private static final GeneralName[] EMPTY_GENERAL_NAMES = new GeneralName[0];
116 private static final DistributionPoint[] EMPTY_DIST_POINTS = new DistributionPoint[0];
117 private static final AlgorithmParameterSpec UNSUPPORTED_SPEC = new AlgorithmParameterSpec() {
118 };
119
120 SecureRandom random;
121 Algorithm algorithm = Algorithm.ecp256;
122 Instant notBefore = Instant.now().minus(1, ChronoUnit.DAYS);
123 Instant notAfter = Instant.now().plus(1, ChronoUnit.DAYS);
124 List<BuilderCallback> modifierCallbacks = new ArrayList<>();
125 List<GeneralName> subjectAlternativeNames = new ArrayList<>();
126 List<DistributionPoint> crlDistributionPoints = new ArrayList<>();
127 BigInteger serial;
128 X500Principal subject;
129 boolean isCertificateAuthority;
130 OptionalInt pathLengthConstraint = OptionalInt.empty();
131 PublicKey publicKey;
132 Set<String> extendedKeyUsage = new TreeSet<>();
133 Extension keyUsage;
134
135
136
137
138
139
140
141 public CertificateBuilder() {
142 }
143
144
145
146
147
148 public CertificateBuilder copy() {
149 CertificateBuilder copy = new CertificateBuilder();
150 copy.random = random;
151 copy.algorithm = algorithm;
152 copy.notBefore = notBefore;
153 copy.notAfter = notAfter;
154 copy.modifierCallbacks = new ArrayList<>(modifierCallbacks);
155 copy.subjectAlternativeNames = new ArrayList<>(subjectAlternativeNames);
156 copy.crlDistributionPoints = new ArrayList<>(crlDistributionPoints);
157 copy.serial = serial;
158 copy.subject = subject;
159 copy.isCertificateAuthority = isCertificateAuthority;
160 copy.pathLengthConstraint = pathLengthConstraint;
161 copy.publicKey = publicKey;
162 copy.keyUsage = keyUsage;
163 copy.extendedKeyUsage = new TreeSet<>(extendedKeyUsage);
164 return copy;
165 }
166
167
168
169
170
171
172 public CertificateBuilder secureRandom(SecureRandom secureRandom) {
173 random = requireNonNull(secureRandom);
174 return this;
175 }
176
177
178
179
180
181
182 public CertificateBuilder notBefore(Instant instant) {
183 notBefore = requireNonNull(instant);
184 return this;
185 }
186
187
188
189
190
191
192 public CertificateBuilder notAfter(Instant instant) {
193 notAfter = requireNonNull(instant);
194 return this;
195 }
196
197
198
199
200
201
202
203 public CertificateBuilder serial(BigInteger serial) {
204 this.serial = serial;
205 return this;
206 }
207
208
209
210
211
212
213 public CertificateBuilder subject(String fqdn) {
214 subject = new X500Principal(requireNonNull(fqdn));
215 return this;
216 }
217
218
219
220
221
222
223 public CertificateBuilder subject(X500Principal name) {
224 subject = requireNonNull(name);
225 return this;
226 }
227
228
229
230
231
232
233
234
235 public CertificateBuilder addSanOtherName(String typeOid, byte[] encodedValue) {
236 subjectAlternativeNames.add(GeneralNameUtils.otherName(typeOid, encodedValue));
237 return this;
238 }
239
240
241
242
243
244
245
246 public CertificateBuilder addSanRfc822Name(String name) {
247 subjectAlternativeNames.add(GeneralNameUtils.rfc822Name(name));
248 return this;
249 }
250
251
252
253
254
255
256 public CertificateBuilder addSanDnsName(String dns) {
257 if (dns.trim().isEmpty()) {
258 throw new IllegalArgumentException("Blank DNS SANs are forbidden by RFC 5280, Section 4.2.1.6.");
259 }
260 subjectAlternativeNames.add(GeneralNameUtils.dnsName(dns));
261 return this;
262 }
263
264
265
266
267
268
269
270
271
272 public CertificateBuilder addSanDirectoryName(String dirName) {
273 subjectAlternativeNames.add(GeneralNameUtils.directoryName(dirName));
274 return this;
275 }
276
277
278
279
280
281
282
283
284 public CertificateBuilder addSanUriName(String uri) throws URISyntaxException {
285 subjectAlternativeNames.add(GeneralNameUtils.uriName(uri));
286 return this;
287 }
288
289
290
291
292
293
294 public CertificateBuilder addSanUriName(URI uri) {
295 subjectAlternativeNames.add(GeneralNameUtils.uriName(uri));
296 return this;
297 }
298
299
300
301
302
303
304
305 public CertificateBuilder addSanIpAddress(String ipAddress) {
306 subjectAlternativeNames.add(GeneralNameUtils.ipAddress(ipAddress));
307 return this;
308 }
309
310
311
312
313
314
315
316 public CertificateBuilder addSanIpAddress(InetAddress ipAddress) {
317 subjectAlternativeNames.add(GeneralNameUtils.ipAddress(ipAddress.getHostAddress()));
318 return this;
319 }
320
321
322
323
324
325
326
327 public CertificateBuilder addSanRegisteredId(String oid) {
328 subjectAlternativeNames.add(GeneralNameUtils.registeredId(oid));
329 return this;
330 }
331
332
333
334
335
336
337
338
339
340
341
342 public CertificateBuilder addCrlDistributionPoint(URI uri) {
343 GeneralName fullName = GeneralNameUtils.uriName(uri);
344 crlDistributionPoints.add(new DistributionPoint(
345 new DistributionPointName(new GeneralNames(fullName)),
346 null,
347 null));
348 return this;
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365 public CertificateBuilder addCrlDistributionPoint(URI uri, X500Principal issuer) {
366 GeneralName fullName = GeneralNameUtils.uriName(uri);
367 GeneralName issuerName = GeneralNameUtils.directoryName(issuer);
368 crlDistributionPoints.add(new DistributionPoint(
369 new DistributionPointName(new GeneralNames(fullName)),
370 null,
371 new GeneralNames(issuerName)));
372 return this;
373 }
374
375
376
377
378
379
380
381
382 public CertificateBuilder setIsCertificateAuthority(boolean isCA) {
383 isCertificateAuthority = isCA;
384 return this;
385 }
386
387
388
389
390
391
392 public CertificateBuilder setPathLengthConstraint(OptionalInt pathLengthConstraint) {
393 this.pathLengthConstraint = requireNonNull(pathLengthConstraint, "pathLengthConstraint");
394 return this;
395 }
396
397
398
399
400
401
402 public CertificateBuilder algorithm(Algorithm algorithm) {
403 requireNonNull(algorithm, "algorithm");
404 if (algorithm.parameterSpec == UNSUPPORTED_SPEC) {
405 throw new UnsupportedOperationException("This algorithm is not supported: " + algorithm);
406 }
407 this.algorithm = algorithm;
408 return this;
409 }
410
411
412
413
414
415
416
417 public CertificateBuilder ecp256() {
418 return algorithm(Algorithm.ecp256);
419 }
420
421
422
423
424
425
426
427 public CertificateBuilder rsa2048() {
428 return algorithm(Algorithm.rsa2048);
429 }
430
431
432
433
434
435
436
437
438
439
440
441
442
443 public CertificateBuilder publicKey(PublicKey key) {
444 publicKey = key;
445 return this;
446 }
447
448 private CertificateBuilder addExtension(String identifierOid, boolean critical, byte[] value) {
449 requireNonNull(identifierOid, "identifierOid");
450 requireNonNull(value, "value");
451 modifierCallbacks.add(builder -> {
452 builder.addExtension(new Extension(
453 new ASN1ObjectIdentifier(identifierOid),
454 critical,
455 value));
456 });
457 return this;
458 }
459
460
461
462
463
464
465
466
467
468 public CertificateBuilder addExtensionOctetString(String identifierOID, boolean critical, byte[] contents) {
469 requireNonNull(identifierOID, "identifierOID");
470 requireNonNull(contents, "contents");
471 modifierCallbacks.add(builder -> {
472 builder.addExtension(new Extension(
473 new ASN1ObjectIdentifier(identifierOID),
474 critical,
475 contents));
476 });
477 return this;
478 }
479
480
481
482
483
484
485
486
487
488
489
490 public CertificateBuilder addExtensionUtf8String(String identifierOID, boolean critical, String value) {
491 try {
492 return addExtension(identifierOID, critical, new DERUTF8String(value).getEncoded("DER"));
493 } catch (IOException e) {
494 throw new UncheckedIOException(e);
495 }
496 }
497
498
499
500
501
502
503
504
505
506
507
508 public CertificateBuilder addExtensionAsciiString(String identifierOID, boolean critical, String value) {
509 try {
510 return addExtension(identifierOID, critical, new DERIA5String(value).getEncoded("DER"));
511 } catch (IOException e) {
512 throw new UncheckedIOException(e);
513 }
514 }
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531 public CertificateBuilder setKeyUsage(boolean critical, KeyUsage... keyUsages) {
532 int maxBit = 0;
533 for (KeyUsage usage : keyUsages) {
534 maxBit = Math.max(usage.bitId, maxBit);
535 }
536 boolean[] bits = new boolean[maxBit + 1];
537 for (KeyUsage usage : keyUsages) {
538 bits[usage.bitId] = true;
539 }
540 int padding = 8 - bits.length % 8;
541 int lenBytes = bits.length / 8 + 1;
542 if (padding == 8) {
543 padding = 0;
544 lenBytes--;
545 }
546 byte[] bytes = new byte[lenBytes];
547 for (int i = 0; i < bits.length; i++) {
548 if (bits[i]) {
549 int byteIndex = i / 8;
550 int bitIndex = i % 8;
551 bytes[byteIndex] |= (byte) (0x80 >>> bitIndex);
552 }
553 }
554
555 try {
556 keyUsage = new Extension(
557 Extension.keyUsage,
558 critical,
559 new DERBitString(bytes, padding).getEncoded("DER"));
560 } catch (IOException e) {
561 throw new UncheckedIOException(e);
562 }
563 return this;
564 }
565
566
567
568
569
570
571
572
573 public CertificateBuilder addExtendedKeyUsage(String oid) {
574 extendedKeyUsage.add(oid);
575 return this;
576 }
577
578
579
580
581
582
583 public CertificateBuilder addExtendedKeyUsage(ExtendedKeyUsage keyUsage) {
584 extendedKeyUsage.add(keyUsage.getOid());
585 return this;
586 }
587
588
589
590
591
592 public CertificateBuilder addExtendedKeyUsageServerAuth() {
593 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_SERVER_AUTH);
594 }
595
596
597
598
599
600 public CertificateBuilder addExtendedKeyUsageClientAuth() {
601 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_CLIENT_AUTH);
602 }
603
604
605
606
607
608 public CertificateBuilder addExtendedKeyUsageCodeSigning() {
609 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_CODE_SIGNING);
610 }
611
612
613
614
615
616 public CertificateBuilder addExtendedKeyUsageEmailProtection() {
617 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_EMAIL_PROTECTION);
618 }
619
620
621
622
623
624 public CertificateBuilder addExtendedKeyUsageTimeStamping() {
625 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_TIME_STAMPING);
626 }
627
628
629
630
631
632 public CertificateBuilder addExtendedKeyUsageOcspSigning() {
633 return addExtendedKeyUsage(ExtendedKeyUsage.PKIX_KP_OCSP_SIGNING);
634 }
635
636
637
638
639
640 public CertificateBuilder addExtendedKeyUsageKerberosClientAuth() {
641 return addExtendedKeyUsage(ExtendedKeyUsage.KERBEROS_KEY_PURPOSE_CLIENT_AUTH);
642 }
643
644
645
646
647
648 public CertificateBuilder addExtendedKeyUsageMicrosoftSmartcardLogin() {
649 return addExtendedKeyUsage(ExtendedKeyUsage.MICROSOFT_SMARTCARD_LOGIN);
650 }
651
652
653
654
655
656
657 public X509Bundle buildSelfSigned() throws Exception {
658 if (publicKey != null) {
659 throw new IllegalStateException("Cannot create a self-signed certificate with a public key from a CSR.");
660 }
661 KeyPair keyPair = generateKeyPair();
662
663 V3TBSCertificateGenerator generator = createCertBuilder(subject, subject, keyPair, algorithm.signatureType);
664
665 addExtensions(generator);
666
667 Signed signed = new Signed(tbsCertToBytes(generator), algorithm.signatureType, keyPair.getPrivate());
668 CertificateFactory factory = CertificateFactory.getInstance("X.509");
669 X509Certificate cert = (X509Certificate) factory.generateCertificate(signed.toInputStream());
670 return X509Bundle.fromRootCertificateAuthority(cert, keyPair);
671 }
672
673
674
675
676
677
678
679 public X509Bundle buildIssuedBy(X509Bundle issuerBundle) throws Exception {
680 String issuerSignAlgorithm = preferredSignatureAlgorithm(issuerBundle.getCertificate().getPublicKey());
681 return buildIssuedBy(issuerBundle, issuerSignAlgorithm);
682 }
683
684
685
686
687
688
689
690 public X509Bundle buildIssuedBy(X509Bundle issuerBundle, String signAlg) throws Exception {
691 final KeyPair keyPair;
692 if (publicKey == null) {
693 keyPair = generateKeyPair();
694 } else {
695 keyPair = new KeyPair(publicKey, null);
696 }
697
698 X500Principal issuerPrincipal = issuerBundle.getCertificate().getSubjectX500Principal();
699 V3TBSCertificateGenerator generator = createCertBuilder(issuerPrincipal, subject, keyPair, signAlg);
700
701 addExtensions(generator);
702
703 PrivateKey issuerPrivateKey = issuerBundle.getKeyPair().getPrivate();
704 if (issuerPrivateKey == null) {
705 throw new IllegalArgumentException(
706 "Cannot sign certificate with issuer bundle that does not have a private key.");
707 }
708 Signed signed = new Signed(tbsCertToBytes(generator), signAlg, issuerPrivateKey);
709 CertificateFactory factory = CertificateFactory.getInstance("X.509");
710 X509Certificate cert = (X509Certificate) factory.generateCertificate(signed.toInputStream());
711 X509Certificate[] issuerPath = issuerBundle.getCertificatePath();
712 X509Certificate[] path = new X509Certificate[issuerPath.length + 1];
713 path[0] = cert;
714 System.arraycopy(issuerPath, 0, path, 1, issuerPath.length);
715 return X509Bundle.fromCertificatePath(path, issuerBundle.getRootCertificate(), keyPair);
716 }
717
718 private static String preferredSignatureAlgorithm(PublicKey key) {
719 if (key instanceof RSAPublicKey) {
720 RSAPublicKey rsa = (RSAPublicKey) key;
721 if (rsa.getModulus().bitLength() < 4096) {
722 return "SHA256withRSA";
723 }
724 return "SHA384withRSA";
725 }
726 if (key instanceof ECPublicKey) {
727 ECPublicKey ec = (ECPublicKey) key;
728 int size = ec.getW().getAffineX().bitLength();
729
730 if (size <= 256) {
731 return "SHA256withECDSA";
732 }
733 if (size <= 384) {
734 return "SHA384withECDSA";
735 }
736 return "SHA512withECDSA";
737 }
738 if (key instanceof DSAPublicKey) {
739 throw new IllegalArgumentException("DSA keys are not supported because they are obsolete.");
740 }
741 String keyAlgorithm = key.getAlgorithm();
742 if ("Ed25519".equals(keyAlgorithm) || "1.3.101.112".equals(keyAlgorithm)) {
743 return "Ed25519";
744 }
745 if ("Ed448".equals(keyAlgorithm) || "1.3.101.113".equals(keyAlgorithm)) {
746 return "Ed448";
747 }
748 if ("EdDSA".equals(keyAlgorithm)) {
749 byte[] encoded = key.getEncoded();
750 if (encoded.length <= 44) {
751 return "Ed25519";
752 }
753 if (encoded.length <= 69) {
754 return "Ed448";
755 }
756 }
757 throw new IllegalArgumentException("Don't know what signature algorithm is best for " + key);
758 }
759
760 private KeyPair generateKeyPair() throws GeneralSecurityException {
761 return algorithm.generateKeyPair(getSecureRandom());
762 }
763
764 private V3TBSCertificateGenerator createCertBuilder(
765 X500Principal issuer, X500Principal subject, KeyPair keyPair, String signAlg) {
766 BigInteger serial = this.serial != null ? this.serial : new BigInteger(159, getSecureRandom());
767 PublicKey pubKey = keyPair.getPublic();
768
769 V3TBSCertificateGenerator generator = new V3TBSCertificateGenerator();
770 generator.setIssuer(X500Name.getInstance(issuer.getEncoded()));
771 if (subject != null) {
772 generator.setSubject(X500Name.getInstance(subject.getEncoded()));
773 }
774 generator.setSerialNumber(new ASN1Integer(serial));
775 generator.setSignature(new AlgorithmIdentifier(new ASN1ObjectIdentifier(
776 Algorithms.oidForAlgorithmName(signAlg))));
777 generator.setStartDate(new Time(Date.from(notBefore)));
778 generator.setEndDate(new Time(Date.from(notAfter)));
779 generator.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()));
780 return generator;
781 }
782
783 private static byte[] tbsCertToBytes(V3TBSCertificateGenerator generator) {
784 try {
785 return generator.generateTBSCertificate().getEncoded("DER");
786 } catch (IOException e) {
787 throw new UncheckedIOException(e);
788 }
789 }
790
791 private SecureRandom getSecureRandom() {
792 SecureRandom rng = random;
793 if (rng == null) {
794 rng = SecureRandomHolder.RANDOM;
795 }
796 return rng;
797 }
798
799 private void addExtensions(V3TBSCertificateGenerator tbsCert) throws Exception {
800 ExtensionsGenerator generator = new ExtensionsGenerator();
801 if (isCertificateAuthority) {
802 final BasicConstraints basicConstraints;
803 if (pathLengthConstraint.isPresent()) {
804 basicConstraints = new BasicConstraints(pathLengthConstraint.getAsInt());
805 } else {
806 basicConstraints = new BasicConstraints(true);
807 }
808 final byte[] basicConstraintsBytes = basicConstraints.getEncoded("DER");
809 generator.addExtension(new Extension(Extension.basicConstraints, true, basicConstraintsBytes));
810 }
811 if (keyUsage != null) {
812 generator.addExtension(keyUsage);
813 }
814
815 if (!extendedKeyUsage.isEmpty()) {
816 KeyPurposeId[] usages = new KeyPurposeId[extendedKeyUsage.size()];
817 String[] usagesStrings = extendedKeyUsage.toArray(EmptyArrays.EMPTY_STRINGS);
818 for (int i = 0; i < usagesStrings.length; i++) {
819 usages[i] = KeyPurposeId.getInstance(new ASN1ObjectIdentifier(usagesStrings[i]));
820 }
821 byte[] der = new org.bouncycastle.asn1.x509.ExtendedKeyUsage(usages).getEncoded("DER");
822 generator.addExtension(new Extension(Extension.extendedKeyUsage, false, der));
823 }
824
825 if (!subjectAlternativeNames.isEmpty()) {
826
827 boolean critical = subject.getName().isEmpty();
828 byte[] result;
829 GeneralNames generalNames = new GeneralNames(subjectAlternativeNames.toArray(EMPTY_GENERAL_NAMES));
830 try {
831 result = generalNames.getEncoded("DER");
832 } catch (IOException e) {
833 throw new UncheckedIOException(e);
834 }
835 generator.addExtension(new Extension(Extension.subjectAlternativeName, critical, result));
836 }
837
838 if (!crlDistributionPoints.isEmpty()) {
839 generator.addExtension(Extension.create(
840 Extension.cRLDistributionPoints,
841 false,
842 new CRLDistPoint(crlDistributionPoints.toArray(EMPTY_DIST_POINTS))));
843 }
844
845 for (BuilderCallback callback : modifierCallbacks) {
846 callback.modify(generator);
847 }
848
849 if (!generator.isEmpty()) {
850 tbsCert.setExtensions(generator.generate());
851 }
852 }
853
854
855
856
857
858 public enum Algorithm {
859
860
861
862
863
864
865 ecp256("EC", new ECGenParameterSpec("secp256r1"), "SHA256withECDSA"),
866
867
868
869
870
871
872 ecp384("EC", new ECGenParameterSpec("secp384r1"), "SHA384withECDSA"),
873
874
875
876
877
878
879 rsa2048("RSA", new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4), "SHA256withRSA"),
880
881
882
883
884
885
886 rsa3072("RSA", new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4), "SHA256withRSA"),
887
888
889
890
891
892
893 rsa4096("RSA", new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4), "SHA384withRSA"),
894
895
896
897
898
899
900 rsa8192("RSA", new RSAKeyGenParameterSpec(8192, RSAKeyGenParameterSpec.F4), "SHA384withRSA"),
901
902
903
904
905
906
907 ed25519("Ed25519", namedParameterSpec("Ed25519"), "Ed25519"),
908
909
910
911
912
913
914 ed448("Ed448", namedParameterSpec("Ed448"), "Ed448"),
915
916
917
918
919
920
921
922 mlDsa44("ML-DSA", namedParameterSpec("ML-DSA-44"), "ML-DSA-44"),
923
924
925
926
927
928
929
930 mlDsa65("ML-DSA", namedParameterSpec("ML-DSA-65"), "ML-DSA-65"),
931
932
933
934
935
936
937
938 mlDsa87("ML-DSA", namedParameterSpec("ML-DSA-87"), "ML-DSA-87");
939
940 final String keyType;
941 final AlgorithmParameterSpec parameterSpec;
942 final String signatureType;
943
944 Algorithm(String keyType, AlgorithmParameterSpec parameterSpec, String signatureType) {
945 this.keyType = keyType;
946 this.parameterSpec = parameterSpec;
947 this.signatureType = signatureType;
948 }
949
950 private static AlgorithmParameterSpec namedParameterSpec(String name) {
951 try {
952 Class<?> cls = Class.forName("java.security.spec.NamedParameterSpec");
953 return (AlgorithmParameterSpec) cls.getConstructor(String.class).newInstance(name);
954 } catch (Exception e) {
955 if ("Ed25519".equals(name)) {
956 return new EdDSAParameterSpec(EdDSAParameterSpec.Ed25519);
957 }
958 if ("Ed448".equals(name)) {
959 return new EdDSAParameterSpec(EdDSAParameterSpec.Ed448);
960 }
961 return UNSUPPORTED_SPEC;
962 }
963 }
964
965
966
967
968
969
970
971
972 public KeyPair generateKeyPair(SecureRandom secureRandom)
973 throws GeneralSecurityException {
974 requireNonNull(secureRandom, "secureRandom");
975
976 if (parameterSpec == UNSUPPORTED_SPEC) {
977 throw new UnsupportedOperationException("This algorithm is not supported: " + this);
978 }
979 if (this == mlDsa44 || this == mlDsa65 || this == mlDsa87) {
980 return genMlDsaKeyPair(secureRandom);
981 }
982 return genKeyPair(secureRandom);
983 }
984
985 private KeyPair genMlDsaKeyPair(SecureRandom secureRandom) throws GeneralSecurityException {
986 final byte[] seed = new byte[32];
987 KeyPair keyPair = genKeyPair(new SecureRandom() {
988 @Override
989 public void nextBytes(byte[] bytes) {
990 assert bytes.length == 32;
991 secureRandom.nextBytes(bytes);
992 System.arraycopy(bytes, 0, seed, 0, seed.length);
993 }
994 });
995 return new KeyPair(keyPair.getPublic(), new MLDSASeedPrivateKey(keyPair.getPrivate(), this, seed));
996 }
997
998 private KeyPair genKeyPair(SecureRandom secureRandom) throws GeneralSecurityException {
999 KeyPairGenerator keyGen = Algorithms.keyPairGenerator(keyType, parameterSpec, secureRandom);
1000 return keyGen.generateKeyPair();
1001 }
1002
1003
1004
1005
1006
1007 public boolean isSupported() {
1008 return parameterSpec != UNSUPPORTED_SPEC;
1009 }
1010 }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021 public enum KeyUsage {
1022
1023
1024
1025
1026 digitalSignature(0),
1027
1028
1029
1030
1031
1032
1033 contentCommitment(1),
1034
1035
1036
1037 keyEncipherment(2),
1038
1039
1040
1041 dataEncipherment(3),
1042
1043
1044
1045 keyAgreement(4),
1046
1047
1048
1049
1050
1051
1052 keyCertSign(5),
1053
1054
1055
1056
1057
1058
1059 cRLSign(6),
1060
1061
1062
1063
1064
1065 encipherOnly(7),
1066
1067
1068
1069
1070
1071 decipherOnly(8);
1072
1073 private final int bitId;
1074
1075 KeyUsage(int bitId) {
1076 this.bitId = bitId;
1077 }
1078 }
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093 public enum ExtendedKeyUsage {
1094
1095
1096
1097 PKIX_KP_SERVER_AUTH(OID_PKIX_KP_SERVER_AUTH),
1098
1099
1100
1101 PKIX_KP_CLIENT_AUTH(OID_PKIX_KP_CLIENT_AUTH),
1102
1103
1104
1105 PKIX_KP_CODE_SIGNING(OID_PKIX_KP_CODE_SIGNING),
1106
1107
1108
1109 PKIX_KP_EMAIL_PROTECTION(OID_PKIX_KP_EMAIL_PROTECTION),
1110
1111
1112
1113 PKIX_KP_TIME_STAMPING(OID_PKIX_KP_TIME_STAMPING),
1114
1115
1116
1117 PKIX_KP_OCSP_SIGNING(OID_PKIX_KP_OCSP_SIGNING),
1118
1119
1120
1121 KERBEROS_KEY_PURPOSE_CLIENT_AUTH(OID_KERBEROS_KEY_PURPOSE_CLIENT_AUTH),
1122
1123
1124
1125 MICROSOFT_SMARTCARD_LOGIN(OID_MICROSOFT_SMARTCARD_LOGIN);
1126
1127 private final String oid;
1128
1129 ExtendedKeyUsage(String oid) {
1130 this.oid = oid;
1131 }
1132
1133 public String getOid() {
1134 return oid;
1135 }
1136 }
1137
1138 @FunctionalInterface
1139 private interface BuilderCallback {
1140 void modify(ExtensionsGenerator builder) throws Exception;
1141 }
1142
1143 private static final class SecureRandomHolder {
1144 private static final SecureRandom RANDOM = new SecureRandom();
1145 }
1146 }