code: /*
   * Copyright (c) 2019 the Eclipse Milo Authors
   *
   * This program and the accompanying materials are made
   * available under the terms of the Eclipse Public License 2.0
   * which is available at https://www.eclipse.org/legal/epl-2.0/
   *
   * SPDX-License-Identifier: EPL-2.0
   */
  
  package org.eclipse.milo.opcua.stack.core.util;
  
  import java.security.KeyPair;
  import java.security.cert.X509Certificate;
  import java.time.LocalDate;
  import java.time.Period;
  import java.time.ZoneId;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  
  import org.bouncycastle.cert.X509v3CertificateBuilder;
  
  public class SelfSignedHttpsCertificateBuilder {
  
      /**
       * Signature Algorithm for SHA256 with RSA.
       */
      private static final String SA_SHA256_RSA = "SHA256withRSA";
  
      private final HttpsCertificateGenerator generator = new HttpsCertificateGenerator();
  
      private Period validityPeriod = Period.ofYears(3);
      private String commonName;
      private List<String> dnsNames = new ArrayList<>();
      private List<String> ipAddresses = new ArrayList<>();
  
      private final KeyPair keyPair;
  
      public SelfSignedHttpsCertificateBuilder(KeyPair keyPair) {
          this.keyPair = keyPair;
      }
  
      public SelfSignedHttpsCertificateBuilder setValidityPeriod(Period validityPeriod) {
          this.validityPeriod = validityPeriod;
          return this;
      }
  
      /**
       * Set the Common Name, which should be the hostname when building an SSL/TLS certificate.
       *
       * @param commonName the hostname to place in the Common Name field.
       * @return {@code this} {@link SelfSignedHttpsCertificateBuilder}.
       */
      public SelfSignedHttpsCertificateBuilder setCommonName(String commonName) {
          this.commonName = commonName;
          return this;
      }
  
      public SelfSignedHttpsCertificateBuilder addDnsName(String dnsName) {
          dnsNames.add(dnsName);
          return this;
      }
  
      public SelfSignedHttpsCertificateBuilder addIpAddress(String ipAddress) {
          ipAddresses.add(ipAddress);
          return this;
      }
  
      public X509Certificate build() throws Exception {
          // Calculate start and end date based on validity period
          LocalDate now = LocalDate.now();
          LocalDate expiration = now.plus(validityPeriod);
  
          Date notBefore = Date.from(now.atStartOfDay(ZoneId.systemDefault()).toInstant());
          Date notAfter = Date.from(expiration.atStartOfDay(ZoneId.systemDefault()).toInstant());
  
          return generator.generateSelfSigned(
              keyPair,
              notBefore,
              notAfter,
              commonName,
              null,
              null,
              null,
              null,
              null,
              null,
              dnsNames,
              ipAddresses,
              SA_SHA256_RSA
          );
      }
  
      private static class HttpsCertificateGenerator extends SelfSignedCertificateGenerator {
  
          @Override
          protected void addKeyUsage(X509v3CertificateBuilder certificateBuilder) {
              // Don't set any KU fields
          }
  
          @Override
          protected void addExtendedKeyUsage(X509v3CertificateBuilder certificateBuilder) {
              // Don't set any EKU fields
          }
  
      }
  
  }
  