// 
// Decompiled by Procyon v0.6.0
// 

package io.netty.handler.ssl.util;

import java.security.PublicKey;
import java.lang.invoke.MethodType;
import java.security.AccessController;
import java.util.List;
import io.netty.util.internal.PlatformDependent;
import java.util.ArrayList;
import java.security.PrivilegedAction;
import java.lang.invoke.MethodHandles;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.util.Random;
import java.math.BigInteger;
import java.util.Date;
import java.security.SecureRandom;
import java.security.KeyPair;
import java.lang.invoke.MethodHandle;
import io.netty.util.internal.logging.InternalLogger;

final class OpenJdkSelfSignedCertGenerator
{
    private static final InternalLogger logger;
    private static final MethodHandle CERT_INFO_SET_HANDLE;
    private static final MethodHandle ISSUER_NAME_CONSTRUCTOR;
    private static final MethodHandle CERT_IMPL_CONSTRUCTOR;
    private static final MethodHandle X509_CERT_INFO_CONSTRUCTOR;
    private static final MethodHandle CERTIFICATE_VERSION_CONSTRUCTOR;
    private static final MethodHandle CERTIFICATE_SUBJECT_NAME_CONSTRUCTOR;
    private static final MethodHandle X500_NAME_CONSTRUCTOR;
    private static final MethodHandle CERTIFICATE_SERIAL_NUMBER_CONSTRUCTOR;
    private static final MethodHandle CERTIFICATE_VALIDITY_CONSTRUCTOR;
    private static final MethodHandle CERTIFICATE_X509_KEY_CONSTRUCTOR;
    private static final MethodHandle CERTIFICATE_ALORITHM_ID_CONSTRUCTOR;
    private static final MethodHandle CERT_IMPL_GET_HANDLE;
    private static final MethodHandle CERT_IMPL_SIGN_HANDLE;
    private static final MethodHandle ALGORITHM_ID_GET_HANDLE;
    private static final boolean SUPPORTED;
    
    static String[] generate(final String fqdn, final KeyPair keypair, final SecureRandom random, final Date notBefore, final Date notAfter, final String algorithm) throws Exception {
        if (!OpenJdkSelfSignedCertGenerator.SUPPORTED) {
            throw new UnsupportedOperationException(OpenJdkSelfSignedCertGenerator.class.getSimpleName() + " not supported on the used JDK version");
        }
        try {
            final PrivateKey key = keypair.getPrivate();
            final Object info = OpenJdkSelfSignedCertGenerator.X509_CERT_INFO_CONSTRUCTOR.invoke();
            final Object owner = OpenJdkSelfSignedCertGenerator.X500_NAME_CONSTRUCTOR.invoke("CN=" + fqdn);
            OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "version", OpenJdkSelfSignedCertGenerator.CERTIFICATE_VERSION_CONSTRUCTOR.invoke(2));
            OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "serialNumber", OpenJdkSelfSignedCertGenerator.CERTIFICATE_SERIAL_NUMBER_CONSTRUCTOR.invoke(new BigInteger(64, random)));
            try {
                OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "subject", OpenJdkSelfSignedCertGenerator.CERTIFICATE_SUBJECT_NAME_CONSTRUCTOR.invoke(owner));
            }
            catch (final CertificateException ex) {
                OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "subject", owner);
            }
            try {
                OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "issuer", OpenJdkSelfSignedCertGenerator.ISSUER_NAME_CONSTRUCTOR.invoke(owner));
            }
            catch (final CertificateException ex) {
                OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "issuer", owner);
            }
            OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "validity", OpenJdkSelfSignedCertGenerator.CERTIFICATE_VALIDITY_CONSTRUCTOR.invoke(notBefore, notAfter));
            OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "key", OpenJdkSelfSignedCertGenerator.CERTIFICATE_X509_KEY_CONSTRUCTOR.invoke(keypair.getPublic()));
            OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "algorithmID", OpenJdkSelfSignedCertGenerator.CERTIFICATE_ALORITHM_ID_CONSTRUCTOR.invoke(OpenJdkSelfSignedCertGenerator.ALGORITHM_ID_GET_HANDLE.invoke("1.2.840.113549.1.1.11")));
            Object cert = OpenJdkSelfSignedCertGenerator.CERT_IMPL_CONSTRUCTOR.invoke(info);
            OpenJdkSelfSignedCertGenerator.CERT_IMPL_SIGN_HANDLE.invoke(cert, key, (Object)(algorithm.equalsIgnoreCase("EC") ? "SHA256withECDSA" : "SHA256withRSA"));
            OpenJdkSelfSignedCertGenerator.CERT_INFO_SET_HANDLE.invoke(info, "algorithmID.algorithm", OpenJdkSelfSignedCertGenerator.CERT_IMPL_GET_HANDLE.invoke(cert, "x509.algorithm"));
            cert = OpenJdkSelfSignedCertGenerator.CERT_IMPL_CONSTRUCTOR.invoke(info);
            OpenJdkSelfSignedCertGenerator.CERT_IMPL_SIGN_HANDLE.invoke(cert, key, (Object)(algorithm.equalsIgnoreCase("EC") ? "SHA256withECDSA" : "SHA256withRSA"));
            final X509Certificate x509Cert = (X509Certificate)cert;
            x509Cert.verify(keypair.getPublic());
            return SelfSignedCertificate.newSelfSignedCertificate(fqdn, key, x509Cert);
        }
        catch (final Throwable cause) {
            if (cause instanceof Exception) {
                throw (Exception)cause;
            }
            if (cause instanceof Error) {
                throw (Error)cause;
            }
            throw new IllegalStateException(cause);
        }
    }
    
    private OpenJdkSelfSignedCertGenerator() {
    }
    
    static {
        logger = InternalLoggerFactory.getInstance(OpenJdkSelfSignedCertGenerator.class);
        final MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle certInfoSetHandle = null;
        MethodHandle x509CertInfoConstructor = null;
        MethodHandle issuerNameConstructor = null;
        MethodHandle certImplConstructor = null;
        MethodHandle x500NameConstructor = null;
        MethodHandle certificateVersionConstructor = null;
        MethodHandle certificateSubjectNameConstructor = null;
        MethodHandle certificateSerialNumberConstructor = null;
        MethodHandle certificateValidityConstructor = null;
        MethodHandle certificateX509KeyConstructor = null;
        MethodHandle certificateAlgorithmIdConstructor = null;
        MethodHandle certImplGetHandle = null;
        MethodHandle certImplSignHandle = null;
        MethodHandle algorithmIdGetHandle = null;
        boolean supported;
        try {
            final Object maybeClasses = AccessController.doPrivileged((PrivilegedAction<Object>)new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    try {
                        final List<Class<?>> classes = new ArrayList<Class<?>>();
                        classes.add(Class.forName("sun.security.x509.X509CertInfo", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.X500Name", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.CertificateIssuerName", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.X509CertImpl", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.CertificateVersion", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.CertificateSubjectName", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.CertificateSerialNumber", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.CertificateValidity", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.CertificateX509Key", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.AlgorithmId", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        classes.add(Class.forName("sun.security.x509.CertificateAlgorithmId", false, PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
                        return classes;
                    }
                    catch (final Throwable cause) {
                        return cause;
                    }
                }
            });
            if (!(maybeClasses instanceof List)) {
                throw (Throwable)maybeClasses;
            }
            final List<Class<?>> classes = (List<Class<?>>)maybeClasses;
            final Class<?> x509CertInfoClass = classes.get(0);
            final Class<?> x500NameClass = classes.get(1);
            final Class<?> certificateIssuerNameClass = classes.get(2);
            final Class<?> x509CertImplClass = classes.get(3);
            final Class<?> certificateVersionClass = classes.get(4);
            final Class<?> certificateSubjectNameClass = classes.get(5);
            final Class<?> certificateSerialNumberClass = classes.get(6);
            final Class<?> certificateValidityClass = classes.get(7);
            final Class<?> certificateX509KeyClass = classes.get(8);
            final Class<?> algorithmIdClass = classes.get(9);
            final Class<?> certificateAlgorithmIdClass = classes.get(10);
            final Object maybeConstructors = AccessController.doPrivileged((PrivilegedAction<Object>)new PrivilegedAction<Object>() {
                final /* synthetic */ MethodHandles.Lookup val$lookup;
                final /* synthetic */ Class val$x509CertInfoClass = x509CertInfoClass;
                final /* synthetic */ Class val$certificateIssuerNameClass = certificateIssuerNameClass;
                final /* synthetic */ Class val$x500NameClass = x500NameClass;
                final /* synthetic */ Class val$x509CertImplClass = x509CertImplClass;
                final /* synthetic */ Class val$certificateVersionClass = certificateVersionClass;
                final /* synthetic */ Class val$certificateSubjectNameClass = certificateSubjectNameClass;
                final /* synthetic */ Class val$certificateSerialNumberClass = certificateSerialNumberClass;
                final /* synthetic */ Class val$certificateValidityClass = certificateValidityClass;
                final /* synthetic */ Class val$certificateX509KeyClass = certificateX509KeyClass;
                final /* synthetic */ Class val$certificateAlgorithmIdClass = certificateAlgorithmIdClass;
                final /* synthetic */ Class val$algorithmIdClass = algorithmIdClass;
                
                @Override
                public Object run() {
                    try {
                        final List<MethodHandle> constructors = new ArrayList<MethodHandle>();
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$x509CertInfoClass.getConstructor((Class<?>[])new Class[0])).asType(MethodType.methodType(this.val$x509CertInfoClass)));
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$certificateIssuerNameClass.getConstructor(this.val$x500NameClass)).asType(MethodType.methodType(this.val$certificateIssuerNameClass, this.val$x500NameClass)));
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$x509CertImplClass.getConstructor(this.val$x509CertInfoClass)).asType(MethodType.methodType(this.val$x509CertImplClass, this.val$x509CertInfoClass)));
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$x500NameClass.getConstructor(String.class)).asType(MethodType.methodType(this.val$x500NameClass, String.class)));
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$certificateVersionClass.getConstructor(Integer.TYPE)).asType(MethodType.methodType(this.val$certificateVersionClass, Integer.TYPE)));
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$certificateSubjectNameClass.getConstructor(this.val$x500NameClass)).asType(MethodType.methodType(this.val$certificateSubjectNameClass, this.val$x500NameClass)));
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$certificateSerialNumberClass.getConstructor(BigInteger.class)).asType(MethodType.methodType(this.val$certificateSerialNumberClass, BigInteger.class)));
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$certificateValidityClass.getConstructor(Date.class, Date.class)).asType(MethodType.methodType(this.val$certificateValidityClass, Date.class, Date.class)));
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$certificateX509KeyClass.getConstructor(PublicKey.class)).asType(MethodType.methodType(this.val$certificateX509KeyClass, PublicKey.class)));
                        constructors.add(this.val$lookup.unreflectConstructor(this.val$certificateAlgorithmIdClass.getConstructor(this.val$algorithmIdClass)).asType(MethodType.methodType(this.val$certificateAlgorithmIdClass, this.val$algorithmIdClass)));
                        return constructors;
                    }
                    catch (final Throwable cause) {
                        return cause;
                    }
                }
            });
            if (!(maybeConstructors instanceof List)) {
                throw (Throwable)maybeConstructors;
            }
            final List<MethodHandle> constructorList = (List<MethodHandle>)maybeConstructors;
            x509CertInfoConstructor = constructorList.get(0);
            issuerNameConstructor = constructorList.get(1);
            certImplConstructor = constructorList.get(2);
            x500NameConstructor = constructorList.get(3);
            certificateVersionConstructor = constructorList.get(4);
            certificateSubjectNameConstructor = constructorList.get(5);
            certificateSerialNumberConstructor = constructorList.get(6);
            certificateValidityConstructor = constructorList.get(7);
            certificateX509KeyConstructor = constructorList.get(8);
            certificateAlgorithmIdConstructor = constructorList.get(9);
            final Object maybeMethodHandles = AccessController.doPrivileged((PrivilegedAction<Object>)new PrivilegedAction<Object>() {
                final /* synthetic */ MethodHandles.Lookup val$lookup;
                final /* synthetic */ Class val$x509CertInfoClass = x509CertInfoClass;
                final /* synthetic */ Class val$x509CertImplClass = x509CertImplClass;
                final /* synthetic */ Class val$algorithmIdClass = algorithmIdClass;
                
                @Override
                public Object run() {
                    try {
                        final List<MethodHandle> methods = new ArrayList<MethodHandle>();
                        methods.add(this.val$lookup.findVirtual(this.val$x509CertInfoClass, "set", MethodType.methodType(Void.TYPE, String.class, Object.class)));
                        methods.add(this.val$lookup.findVirtual(this.val$x509CertImplClass, "get", MethodType.methodType(Object.class, String.class)));
                        methods.add(this.val$lookup.findVirtual(this.val$x509CertImplClass, "sign", MethodType.methodType(Void.TYPE, PrivateKey.class, String.class)));
                        methods.add(this.val$lookup.findStatic(this.val$algorithmIdClass, "get", MethodType.methodType(this.val$algorithmIdClass, String.class)));
                        return methods;
                    }
                    catch (final Throwable cause) {
                        return cause;
                    }
                }
            });
            if (!(maybeMethodHandles instanceof List)) {
                throw (Throwable)maybeMethodHandles;
            }
            final List<MethodHandle> methodHandles = (List<MethodHandle>)maybeMethodHandles;
            certInfoSetHandle = methodHandles.get(0);
            certImplGetHandle = methodHandles.get(1);
            certImplSignHandle = methodHandles.get(2);
            algorithmIdGetHandle = methodHandles.get(3);
            supported = true;
        }
        catch (final Throwable cause) {
            supported = false;
            OpenJdkSelfSignedCertGenerator.logger.debug(OpenJdkSelfSignedCertGenerator.class.getSimpleName() + " not supported", cause);
        }
        CERT_INFO_SET_HANDLE = certInfoSetHandle;
        X509_CERT_INFO_CONSTRUCTOR = x509CertInfoConstructor;
        ISSUER_NAME_CONSTRUCTOR = issuerNameConstructor;
        CERTIFICATE_VERSION_CONSTRUCTOR = certificateVersionConstructor;
        CERTIFICATE_SUBJECT_NAME_CONSTRUCTOR = certificateSubjectNameConstructor;
        CERT_IMPL_CONSTRUCTOR = certImplConstructor;
        X500_NAME_CONSTRUCTOR = x500NameConstructor;
        CERTIFICATE_SERIAL_NUMBER_CONSTRUCTOR = certificateSerialNumberConstructor;
        CERTIFICATE_VALIDITY_CONSTRUCTOR = certificateValidityConstructor;
        CERTIFICATE_X509_KEY_CONSTRUCTOR = certificateX509KeyConstructor;
        CERT_IMPL_GET_HANDLE = certImplGetHandle;
        CERT_IMPL_SIGN_HANDLE = certImplSignHandle;
        ALGORITHM_ID_GET_HANDLE = algorithmIdGetHandle;
        CERTIFICATE_ALORITHM_ID_CONSTRUCTOR = certificateAlgorithmIdConstructor;
        SUPPORTED = supported;
    }
}
