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