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.PublicKey;
  import java.security.cert.X509Certificate;
  import java.security.interfaces.ECPublicKey;
  import java.security.interfaces.RSAPublicKey;
  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.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  public class SelfSignedCertificateBuilder {
  
      /**
       * Signature Algorithm for SHA1 with RSA.
       * <p>
       * SHA1 was broken in 2017 and this algorithm should not be used.
       */
      public static final String SA_SHA1_RSA = "SHA1withRSA";
  
      /**
       * Signature Algorithm for SHA256 with RSA.
       */
      public static final String SA_SHA256_RSA = "SHA256withRSA";
  
      /**
       * Signature Algorithm for SHA256 with ECDSA.
       * <p>
       * May only be uses with EC-based KeyPairs and security profiles.
       */
      public static final String SA_SHA256_ECDSA = "SHA256withECDSA";
  
      private Period validityPeriod = Period.ofYears(3);
  
      private String commonName = "";
      private String organization = "";
      private String organizationalUnit = "";
      private String localityName = "";
      private String stateName = "";
      private String countryCode = "";
  
      private String applicationUri = "";
      private List<String> dnsNames = new ArrayList<>();
      private List<String> ipAddresses = new ArrayList<>();
      private String signatureAlgorithm = SA_SHA256_RSA;
  
      private final KeyPair keyPair;
      private final SelfSignedCertificateGenerator generator;
  
      public SelfSignedCertificateBuilder(KeyPair keyPair) {
          this(keyPair, new SelfSignedCertificateGenerator());
      }
  
      public SelfSignedCertificateBuilder(KeyPair keyPair, SelfSignedCertificateGenerator generator) {
          this.keyPair = keyPair;
          this.generator = generator;
  
          PublicKey publicKey = keyPair.getPublic();
  
          if (publicKey instanceof RSAPublicKey) {
              signatureAlgorithm = SA_SHA256_RSA;
  
              int bitLength = ((RSAPublicKey) keyPair.getPublic()).getModulus().bitLength();
  
              if (bitLength <= 1024) {
                  Logger logger = LoggerFactory.getLogger(getClass());
                  logger.warn("Using legacy key size: {}", bitLength);
              }
          } else if (keyPair.getPublic() instanceof ECPublicKey) {
              signatureAlgorithm = SA_SHA256_ECDSA;
          }
      }
  
      public SelfSignedCertificateBuilder setValidityPeriod(Period validityPeriod) {
          this.validityPeriod = validityPeriod;
          return this;
      }
  
      public SelfSignedCertificateBuilder setCommonName(String commonName) {
          this.commonName = commonName;
          return this;
      }
  
      public SelfSignedCertificateBuilder setOrganization(String organization) {
          this.organization = organization;
          return this;
      }
  
      public SelfSignedCertificateBuilder setOrganizationalUnit(String organizationalUnit) {
          this.organizationalUnit = organizationalUnit;
          return this;
      }
  
      public SelfSignedCertificateBuilder setLocalityName(String localityName) {
          this.localityName = localityName;
          return this;
      }
  
      public SelfSignedCertificateBuilder setStateName(String stateName) {
          this.stateName = stateName;
          return this;
      }
  
      public SelfSignedCertificateBuilder setCountryCode(String countryCode) {
          this.countryCode = countryCode;
          return this;
      }
  
      public SelfSignedCertificateBuilder setApplicationUri(String applicationUri) {
          this.applicationUri = applicationUri;
          return this;
      }
  
      public SelfSignedCertificateBuilder addDnsName(String dnsName) {
          dnsNames.add(dnsName);
          return this;
      }
  
      public SelfSignedCertificateBuilder addIpAddress(String ipAddress) {
          ipAddresses.add(ipAddress);
          return this;
      }
  
      public SelfSignedCertificateBuilder setSignatureAlgorithm(String signatureAlgorithm) {
          this.signatureAlgorithm = signatureAlgorithm;
          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,
              organization,
              organizationalUnit,
              localityName,
              stateName,
              countryCode,
              applicationUri,
              dnsNames,
              ipAddresses,
              signatureAlgorithm
          );
      }
  
  }
  