/**
  * Create an intermediate CA certificate.
  *
  * @param issuer the certified keypair for issuing the certificate
  * @param publicKey the public key to certify
  * @param dn the distinguished name for the new the certificate.
  * @param validity the validity of the certificate from now in days.
  * @return a certified public key.
  * @throws IOException in case on error while reading the public key.
  * @throws GeneralSecurityException in case of error.
  */
 public CertifiedPublicKey issueIntermediateCertificate(
     CertifiedKeyPair issuer, PublicKeyParameters publicKey, String dn, int validity)
     throws IOException, GeneralSecurityException {
   return certificateGeneratorFactory
       .getInstance(
           CertifyingSigner.getInstance(true, issuer, signerFactory),
           new X509CertificateGenerationParameters(
               validity,
               extensionBuilder
                   .get()
                   .addBasicConstraints(0)
                   .addKeyUsage(EnumSet.of(KeyUsage.keyCertSign, KeyUsage.cRLSign))
                   .build()))
       .generate(new DistinguishedName(dn), publicKey, new X509CertificateParameters());
 }
 /**
  * Create a self-signed certificate for a Root CA.
  *
  * @param keyPair the keypair to issue the certificate for and used for signing it.
  * @param dn the distinguished name for the new the certificate.
  * @param validity the validity of the certificate from now in days.
  * @return a certified public key.
  * @throws IOException in case on error while reading the public key.
  * @throws GeneralSecurityException in case of error.
  */
 public CertifiedKeyPair issueRootCACertificate(AsymmetricKeyPair keyPair, String dn, int validity)
     throws IOException, GeneralSecurityException {
   return new CertifiedKeyPair(
       keyPair.getPrivate(),
       certificateGeneratorFactory
           .getInstance(
               signerFactory.getInstance(true, keyPair.getPrivate()),
               new X509CertificateGenerationParameters(
                   validity,
                   extensionBuilder
                       .get()
                       .addBasicConstraints(true)
                       .addKeyUsage(true, EnumSet.of(KeyUsage.keyCertSign, KeyUsage.cRLSign))
                       .build()))
           .generate(
               new DistinguishedName(dn), keyPair.getPublic(), new X509CertificateParameters()));
 }
  /**
   * Create an end entity certificate. By default, the key can be used for encryption and signing.
   * If the end entity contains some alternate subject names of type X509Rfc822Name a extended email
   * protection usage is added. If the end entity contains some alternate subject names of type
   * X509DnsName or X509IpAddress extended server and client authentication usages are added.
   *
   * @param issuer the keypair for issuing the certificate
   * @param publicKey the public key to certify
   * @param dn the distinguished name for the new the certificate.
   * @param validity the validity of the certificate from now in days.
   * @param subjectAltName the alternative names for the certificate
   * @return a certified public key.
   * @throws IOException in case on error while reading the public key.
   * @throws GeneralSecurityException in case of error.
   */
  public CertifiedPublicKey issueCertificate(
      CertifiedKeyPair issuer,
      PublicKeyParameters publicKey,
      String dn,
      int validity,
      List<X509GeneralName> subjectAltName)
      throws IOException, GeneralSecurityException {
    X509CertificateParameters params;
    X509ExtensionBuilder builder =
        extensionBuilder
            .get()
            .addKeyUsage(EnumSet.of(KeyUsage.digitalSignature, KeyUsage.dataEncipherment));

    if (subjectAltName != null) {
      params =
          new X509CertificateParameters(
              extensionBuilder
                  .get()
                  .addSubjectAltName(false, subjectAltName.toArray(new X509GeneralName[] {}))
                  .build());
      Set<String> extUsage = new HashSet<String>();
      for (X509GeneralName genName : subjectAltName) {
        if (genName instanceof X509Rfc822Name) {
          extUsage.add(ExtendedKeyUsages.EMAIL_PROTECTION);
        } else if (genName instanceof X509DnsName || genName instanceof X509IpAddress) {
          extUsage.add(ExtendedKeyUsages.SERVER_AUTH);
          extUsage.add(ExtendedKeyUsages.CLIENT_AUTH);
        }
        builder.addExtendedKeyUsage(false, new ExtendedKeyUsages(extUsage));
      }
    } else {
      params = new X509CertificateParameters();
    }

    return certificateGeneratorFactory
        .getInstance(
            CertifyingSigner.getInstance(true, issuer, signerFactory),
            new X509CertificateGenerationParameters(validity, builder.build()))
        .generate(new DistinguishedName(dn), publicKey, params);
  }