View Javadoc
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.handler.ssl.util;
17  
18  import io.netty.pkitesting.CertificateBuilder;
19  import io.netty.pkitesting.X509Bundle;
20  
21  import java.security.SecureRandom;
22  import java.time.Instant;
23  import java.util.Date;
24  
25  import static io.netty.handler.ssl.util.SelfSignedCertificate.newSelfSignedCertificate;
26  
27  final class CertificateBuilderCertGenerator {
28      private CertificateBuilderCertGenerator() {
29      }
30  
31      static boolean isAvailable() {
32          try {
33              new CertificateBuilder();
34              return true;
35          } catch (Throwable ignore) {
36              return false;
37          }
38      }
39  
40      static void generate(SelfSignedCertificate.Builder config) throws Exception {
41          String fqdn = config.fqdn;
42          Date notBefore = config.notBefore;
43          Date notAfter = config.notAfter;
44          String algorithm = config.algorithm;
45          SecureRandom random = config.random;
46          int bits = config.bits;
47          CertificateBuilder builder = new CertificateBuilder();
48          builder.setIsCertificateAuthority(true);
49          if (fqdn.contains("=")) {
50              builder.subject(fqdn);
51          } else {
52              builder.subject("CN=" + fqdn);
53          }
54          builder.notBefore(Instant.ofEpochMilli(notBefore.getTime()));
55          builder.notAfter(Instant.ofEpochMilli(notAfter.getTime()));
56          if (random != null) {
57              builder.secureRandom(random);
58          }
59          if ("RSA".equals(algorithm)) {
60              CertificateBuilder.Algorithm alg;
61              switch (bits) {
62                  case 2048: alg = CertificateBuilder.Algorithm.rsa2048; break;
63                  case 3072: alg = CertificateBuilder.Algorithm.rsa3072; break;
64                  case 4096: alg = CertificateBuilder.Algorithm.rsa4096; break;
65                  case 8192: alg = CertificateBuilder.Algorithm.rsa8192; break;
66                  default:
67                      throw new IllegalArgumentException("Unsupported RSA bit-width: " + bits);
68              }
69              builder.algorithm(alg);
70          } else if ("EC".equals(algorithm)) {
71              if (bits == 256) {
72                  builder.algorithm(CertificateBuilder.Algorithm.ecp256);
73              } else if (bits == 384) {
74                  builder.algorithm(CertificateBuilder.Algorithm.ecp384);
75              } else {
76                  throw new IllegalArgumentException("Unsupported EC-P bit-width: " + bits);
77              }
78          }
79          X509Bundle bundle = builder.buildSelfSigned();
80          config.paths = newSelfSignedCertificate(fqdn, bundle.getKeyPair().getPrivate(), bundle.getCertificate());
81          config.keypair = bundle.getKeyPair();
82          config.privateKey = bundle.getKeyPair().getPrivate();
83      }
84  }