package com.github.tomakehurst.wiremock.crypto;

import sun.security.x509.AlgorithmId;
import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateX509Key;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;

import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;

import static com.github.tomakehurst.wiremock.common.Exceptions.throwUnchecked;
import static java.util.Objects.requireNonNull;

public class X509CertificateSpecification implements CertificateSpecification {

    private final X509CertificateVersion version;
    private final String subject;
    private final String issuer;
    // java.time is JDK8 on
    private final Date notBefore;
    private final Date notAfter;

    public X509CertificateSpecification(
        X509CertificateVersion version,
        String subject,
        String issuer,
        Date notBefore,
        Date notAfter
    ) {
        this.version = requireNonNull(version);
        this.subject = requireNonNull(subject);
        this.issuer = requireNonNull(issuer);
        this.notBefore = requireNonNull(notBefore);
        this.notAfter = requireNonNull(notAfter);
    }

    @Override
    public X509Certificate certificateFor(KeyPair keyPair) throws CertificateException, InvalidKeyException, SignatureException {
        try {
            SecureRandom random = new SecureRandom();

            X509CertInfo info = new X509CertInfo();
            info.set(X509CertInfo.VERSION, version.getVersion());
            info.set(X509CertInfo.SUBJECT, new X500Name(subject));
            info.set(X509CertInfo.ISSUER, new X500Name(issuer));
            info.set(X509CertInfo.VALIDITY, new CertificateValidity(notBefore, notAfter));

            info.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));
            info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(new BigInteger(64, random)));
            info.set(X509CertInfo.ALGORITHM_ID,
                    new CertificateAlgorithmId(new AlgorithmId(AlgorithmId.sha1WithRSAEncryption_oid)));

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

            // Update the algorithm and sign again.
            info.set(CertificateAlgorithmId.NAME + '.' + CertificateAlgorithmId.ALGORITHM, cert.get(X509CertImpl.SIG_ALG));
            cert = new X509CertImpl(info);
            cert.sign(keyPair.getPrivate(), "SHA256withRSA");
            cert.verify(keyPair.getPublic());

            return cert;
        } catch (IOException | NoSuchAlgorithmException | NoSuchProviderException e) {
            return throwUnchecked(e, null);
        }
    }
}

@@ -165,28 +165,125 @@
 tificate
-SerialNumber
+IssuerName;%0Aimport sun.security.x509.CertificateSerialNumber;%0Aimport sun.security.x509.CertificateSubjectName
 ;%0Aimport
@@ -1172,22 +1172,24 @@
 e final 
-String
+X500Name
  subject
@@ -1208,22 +1208,24 @@
 e final 
-String
+X500Name
  issuer;
@@ -1252,16 +1252,18 @@
  JDK8 on
+ly
 %0A    pri
@@ -1502,16 +1502,35 @@
 er%0A    )
+ throws IOException
  %7B%0A     
@@ -1595,16 +1595,29 @@
 bject = 
+new X500Name(
 requireN
@@ -1631,16 +1631,17 @@
 subject)
+)
 ;%0A      
@@ -1652,24 +1652,37 @@
 is.issuer = 
+new X500Name(
 requireNonNu
@@ -1691,16 +1691,17 @@
 (issuer)
+)
 ;%0A      
@@ -2138,139 +2138,710 @@
 ));%0A
-            info.set(X509CertInfo.SUBJECT, new X500Name(subject));%0A            info.set(X509CertInfo.ISSUER, new X500Name(issuer));
+%0A            // On Java %3C= 1.7 it has to be a %60CertificateSubjectName%60%0A            // On Java %3E= 1.8 it has to be an %60X500Name%60%0A            try %7B%0A                info.set(X509CertInfo.SUBJECT, subject);%0A            %7D catch (CertificateException ignore) %7B%0A                info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(subject));%0A            %7D%0A%0A            // On Java %3C= 1.7 it has to be a %60CertificateIssuerName%60%0A            // On Java %3E= 1.8 it has to be an %60X500Name%60%0A            try %7B%0A                info.set(X509CertInfo.ISSUER, issuer);%0A            %7D catch (CertificateException ignore) %7B%0A                info.set(X509CertInfo.ISSUER, new CertificateIssuerName(issuer));%0A            %7D%0A
 %0A   

Fix java7 build