private X509Certificate generate(PublicKey publicKey, PrivateKey privateKey) {
    Date from = new Date();
    Date to = new Date(from.getTime() + days * 86_400_000L);

    CertificateValidity interval = new CertificateValidity(from, to);
    BigInteger sn = new BigInteger(64, new SecureRandom());

    X509CertInfo info = new X509CertInfo();

    try {
      info.set(X509CertInfo.VALIDITY, interval);
      info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
      info.set(X509CertInfo.SUBJECT, name);
      info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
      info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
      AlgorithmId algo = AlgorithmId.get("MD5withRSA");
      info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

      if (issuer == null) {
        // This is a self-signed certificate
        info.set(X509CertInfo.ISSUER, name);
      } else {
        info.set(X509CertInfo.ISSUER, issuer.getCertificate().getSubjectDN());
      }

      CertificateExtensions extensions = new CertificateExtensions();

      byte[] keyIdBytes = new KeyIdentifier(publicKey).getIdentifier();
      SubjectKeyIdentifierExtension keyIdentifier = new SubjectKeyIdentifierExtension(keyIdBytes);
      extensions.set(SubjectKeyIdentifierExtension.NAME, keyIdentifier);

      GeneralNames subjectAltNames = san();
      if (!subjectAltNames.isEmpty()) {
        SubjectAlternativeNameExtension altNames =
            new SubjectAlternativeNameExtension(subjectAltNames);
        extensions.set(SubjectAlternativeNameExtension.NAME, altNames);
      }

      if (isCA) {
        KeyUsageExtension usageExtension = new KeyUsageExtension();
        usageExtension.set(KeyUsageExtension.KEY_CERTSIGN, true);
        extensions.set(KeyUsageExtension.NAME, usageExtension);

        BasicConstraintsExtension basicConstraints = new BasicConstraintsExtension(true, 0);
        extensions.set(BasicConstraintsExtension.NAME, basicConstraints);
      }

      if (!extensions.getAllExtensions().isEmpty()) {
        info.set(X509CertInfo.EXTENSIONS, extensions);
      }

      // Sign the cert to identify the algorithm that's used.
      X509CertImpl cert = new X509CertImpl(info);
      cert.sign(privateKey, algorithm);

      // Update the algorithm, and resign.
      algo = (AlgorithmId) cert.get(X509CertImpl.SIG_ALG);
      info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
      cert = new X509CertImpl(info);
      cert.sign(privateKey, algorithm);

      return cert;
    } catch (Exception ex) {
      throw new RuntimeException("Unable to create certificate", ex);
    }
  }
Class which allows easily building certificates. It can also be used to build
Certificate Authorities. The class is intended to be used in conjunction with {@link CertStores}
to facilitate building key and trust stores.
geode-junit/src/main/java/org/apache/geode/cache/ssl/CertificateBuilder.java