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

package io.netty.handler.codec.quic;

import java.security.Provider;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.security.cert.Certificate;
import org.jetbrains.annotations.Nullable;
import java.security.Key;
import java.util.Date;
import java.security.KeyStoreSpi;
import javax.net.ssl.KeyManager;
import javax.net.ssl.ManagerFactoryParameters;
import java.security.KeyStore;
import io.netty.util.internal.ObjectUtil;
import java.security.cert.X509Certificate;
import java.security.UnrecoverableKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.KeyStoreException;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.io.File;
import java.util.Objects;
import javax.net.ssl.KeyManagerFactorySpi;
import javax.net.ssl.KeyManagerFactory;

public final class BoringSSLKeylessManagerFactory extends KeyManagerFactory
{
    final BoringSSLAsyncPrivateKeyMethod privateKeyMethod;
    
    private BoringSSLKeylessManagerFactory(final KeyManagerFactory keyManagerFactory, final BoringSSLAsyncPrivateKeyMethod privateKeyMethod) {
        super(new KeylessManagerFactorySpi(keyManagerFactory), keyManagerFactory.getProvider(), keyManagerFactory.getAlgorithm());
        this.privateKeyMethod = Objects.requireNonNull(privateKeyMethod, "privateKeyMethod");
    }
    
    public static BoringSSLKeylessManagerFactory newKeyless(final BoringSSLAsyncPrivateKeyMethod privateKeyMethod, final File chain) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
        try (final InputStream chainInputStream = Files.newInputStream(chain.toPath(), new OpenOption[0])) {
            return newKeyless(privateKeyMethod, chainInputStream);
        }
    }
    
    public static BoringSSLKeylessManagerFactory newKeyless(final BoringSSLAsyncPrivateKeyMethod privateKeyMethod, final InputStream chain) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
        return newKeyless(privateKeyMethod, QuicSslContext.toX509Certificates0(chain));
    }
    
    public static BoringSSLKeylessManagerFactory newKeyless(final BoringSSLAsyncPrivateKeyMethod privateKeyMethod, final X509Certificate... certificateChain) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
        ObjectUtil.checkNotNull(certificateChain, "certificateChain");
        final KeyStore store = new KeylessKeyStore((X509Certificate[])certificateChain.clone());
        store.load(null, null);
        final BoringSSLKeylessManagerFactory factory = new BoringSSLKeylessManagerFactory(KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()), privateKeyMethod);
        factory.init(store, null);
        return factory;
    }
    
    private static final class KeylessManagerFactorySpi extends KeyManagerFactorySpi
    {
        private final KeyManagerFactory keyManagerFactory;
        
        KeylessManagerFactorySpi(final KeyManagerFactory keyManagerFactory) {
            this.keyManagerFactory = Objects.requireNonNull(keyManagerFactory, "keyManagerFactory");
        }
        
        @Override
        protected void engineInit(final KeyStore ks, final char[] password) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
            this.keyManagerFactory.init(ks, password);
        }
        
        @Override
        protected void engineInit(final ManagerFactoryParameters spec) {
            throw new UnsupportedOperationException("Not supported");
        }
        
        @Override
        protected KeyManager[] engineGetKeyManagers() {
            return this.keyManagerFactory.getKeyManagers();
        }
    }
    
    private static final class KeylessKeyStore extends KeyStore
    {
        private static final String ALIAS = "key";
        
        private KeylessKeyStore(final X509Certificate[] certificateChain) {
            super(new KeyStoreSpi() {
                private final Date creationDate = new Date();
                
                @Nullable
                @Override
                public Key engineGetKey(final String alias, final char[] password) {
                    if (this.engineContainsAlias(alias)) {
                        return BoringSSLKeylessPrivateKey.INSTANCE;
                    }
                    return null;
                }
                
                @Override
                public Certificate[] engineGetCertificateChain(final String alias) {
                    return (Certificate[])(this.engineContainsAlias(alias) ? ((Certificate[])certificateChain.clone()) : null);
                }
                
                @Nullable
                @Override
                public Certificate engineGetCertificate(final String alias) {
                    return this.engineContainsAlias(alias) ? certificateChain[0] : null;
                }
                
                @Nullable
                @Override
                public Date engineGetCreationDate(final String alias) {
                    return this.engineContainsAlias(alias) ? this.creationDate : null;
                }
                
                @Override
                public void engineSetKeyEntry(final String alias, final Key key, final char[] password, final Certificate[] chain) throws KeyStoreException {
                    throw new KeyStoreException("Not supported");
                }
                
                @Override
                public void engineSetKeyEntry(final String alias, final byte[] key, final Certificate[] chain) throws KeyStoreException {
                    throw new KeyStoreException("Not supported");
                }
                
                @Override
                public void engineSetCertificateEntry(final String alias, final Certificate cert) throws KeyStoreException {
                    throw new KeyStoreException("Not supported");
                }
                
                @Override
                public void engineDeleteEntry(final String alias) throws KeyStoreException {
                    throw new KeyStoreException("Not supported");
                }
                
                @Override
                public Enumeration<String> engineAliases() {
                    return Collections.enumeration(Collections.singleton("key"));
                }
                
                @Override
                public boolean engineContainsAlias(final String alias) {
                    return "key".equals(alias);
                }
                
                @Override
                public int engineSize() {
                    return 1;
                }
                
                @Override
                public boolean engineIsKeyEntry(final String alias) {
                    return this.engineContainsAlias(alias);
                }
                
                @Override
                public boolean engineIsCertificateEntry(final String alias) {
                    return this.engineContainsAlias(alias);
                }
                
                @Nullable
                @Override
                public String engineGetCertificateAlias(final Certificate cert) {
                    if (cert instanceof X509Certificate) {
                        for (final X509Certificate x509Certificate : certificateChain) {
                            if (x509Certificate.equals(cert)) {
                                return "key";
                            }
                        }
                    }
                    return null;
                }
                
                @Override
                public void engineStore(final OutputStream stream, final char[] password) {
                    throw new UnsupportedOperationException();
                }
                
                @Override
                public void engineLoad(@Nullable final InputStream stream, final char[] password) {
                    if (stream != null && password != null) {
                        throw new UnsupportedOperationException();
                    }
                }
            }, null, "keyless");
        }
    }
}
