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

package io.netty.handler.ssl;

import io.netty.util.CharsetUtil;
import javax.net.ssl.SSLEngine;
import io.netty.util.internal.logging.InternalLoggerFactory;
import javax.net.ssl.SSLSessionContext;
import io.netty.internal.tcnative.CertificateVerifier;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
import io.netty.internal.tcnative.SniHostNameMatcher;
import io.netty.internal.tcnative.SSL;
import io.netty.buffer.ByteBufAllocator;
import java.security.KeyStore;
import io.netty.internal.tcnative.CertificateCallback;
import io.netty.util.internal.ObjectUtil;
import io.netty.internal.tcnative.SSLContext;
import javax.net.ssl.SNIServerName;
import java.util.List;
import java.security.cert.Certificate;
import javax.net.ssl.SSLException;
import java.util.Map;
import javax.net.ssl.KeyManagerFactory;
import java.security.PrivateKey;
import javax.net.ssl.TrustManagerFactory;
import java.security.cert.X509Certificate;
import io.netty.util.internal.logging.InternalLogger;

public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext
{
    private static final InternalLogger logger;
    private static final byte[] ID;
    private final OpenSslServerSessionContext sessionContext;
    
    ReferenceCountedOpenSslServerContext(final X509Certificate[] trustCertCollection, final TrustManagerFactory trustManagerFactory, final X509Certificate[] keyCertChain, final PrivateKey key, final String keyPassword, final KeyManagerFactory keyManagerFactory, final Iterable<String> ciphers, final CipherSuiteFilter cipherFilter, final ApplicationProtocolConfig apn, final long sessionCacheSize, final long sessionTimeout, final ClientAuth clientAuth, final String[] protocols, final boolean startTls, final boolean enableOcsp, final String keyStore, final ResumptionController resumptionController, final Map.Entry<SslContextOption<?>, Object>... options) throws SSLException {
        this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, ReferenceCountedOpenSslContext.toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, enableOcsp, keyStore, resumptionController, options);
    }
    
    ReferenceCountedOpenSslServerContext(final X509Certificate[] trustCertCollection, final TrustManagerFactory trustManagerFactory, final X509Certificate[] keyCertChain, final PrivateKey key, final String keyPassword, final KeyManagerFactory keyManagerFactory, final Iterable<String> ciphers, final CipherSuiteFilter cipherFilter, final OpenSslApplicationProtocolNegotiator apn, final long sessionCacheSize, final long sessionTimeout, final ClientAuth clientAuth, final String[] protocols, final boolean startTls, final boolean enableOcsp, final String keyStore, final ResumptionController resumptionController, final Map.Entry<SslContextOption<?>, Object>... options) throws SSLException {
        super(ciphers, cipherFilter, apn, 1, keyCertChain, clientAuth, protocols, startTls, null, enableOcsp, true, null, resumptionController, options);
        boolean success = false;
        try {
            this.sessionContext = newSessionContext(this, this.ctx, this.engines, trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, keyStore, sessionCacheSize, sessionTimeout, resumptionController, ReferenceCountedOpenSslContext.isJdkSignatureFallbackEnabled(options));
            if (ReferenceCountedOpenSslServerContext.SERVER_ENABLE_SESSION_TICKET) {
                this.sessionContext.setTicketKeys(new OpenSslSessionTicketKey[0]);
            }
            success = true;
        }
        finally {
            if (!success) {
                this.release();
            }
        }
    }
    
    @Override
    public OpenSslServerSessionContext sessionContext() {
        return this.sessionContext;
    }
    
    static OpenSslServerSessionContext newSessionContext(final ReferenceCountedOpenSslContext thiz, final long ctx, final Map<Long, ReferenceCountedOpenSslEngine> engines, final X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, final X509Certificate[] keyCertChain, final PrivateKey key, final String keyPassword, KeyManagerFactory keyManagerFactory, final String keyStore, final long sessionCacheSize, final long sessionTimeout, final ResumptionController resumptionController, final boolean fallbackToJdkSignatureProviders) throws SSLException {
        OpenSslKeyMaterialProvider keyMaterialProvider = null;
        try {
            try {
                SSLContext.setVerify(ctx, 0, 10);
                if (keyManagerFactory == null && key != null && key.getEncoded() == null) {
                    if (!fallbackToJdkSignatureProviders) {
                        throw new SSLException("Private key requiring alternative signature provider detected (such as hardware security key, smart card, or remote signing service) but alternative key fallback is disabled.");
                    }
                    final X509TrustManager manager;
                    keyMaterialProvider = ReferenceCountedOpenSslContext.setupSecurityProviderSignatureSource(thiz, ctx, keyCertChain, key, manager -> new OpenSslServerCertificateCallback(engines, manager));
                }
                else if (!OpenSsl.useKeyManagerFactory()) {
                    if (keyManagerFactory != null) {
                        throw new IllegalArgumentException("KeyManagerFactory not supported with external keys");
                    }
                    ObjectUtil.checkNotNull(keyCertChain, "keyCertChain");
                    ReferenceCountedOpenSslContext.setKeyMaterial(ctx, keyCertChain, key, keyPassword);
                }
                else {
                    if (keyManagerFactory == null) {
                        keyManagerFactory = ReferenceCountedOpenSslContext.certChainToKeyManagerFactory(keyCertChain, key, keyPassword, keyStore);
                    }
                    keyMaterialProvider = ReferenceCountedOpenSslContext.providerFor(keyManagerFactory, keyPassword);
                    SSLContext.setCertificateCallback(ctx, (CertificateCallback)new OpenSslServerCertificateCallback(engines, new OpenSslKeyMaterialManager(keyMaterialProvider, thiz.hasTmpDhKeys)));
                }
            }
            catch (final Exception e) {
                throw new SSLException("failed to set certificate and key", e);
            }
            try {
                if (trustCertCollection != null) {
                    trustManagerFactory = SslContext.buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
                }
                else if (trustManagerFactory == null) {
                    trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    trustManagerFactory.init((KeyStore)null);
                }
                final X509TrustManager manager = ReferenceCountedOpenSslContext.chooseTrustManager(trustManagerFactory.getTrustManagers(), resumptionController);
                setVerifyCallback(ctx, engines, manager);
                final X509Certificate[] issuers = manager.getAcceptedIssuers();
                if (issuers != null && issuers.length > 0) {
                    long bio = 0L;
                    try {
                        bio = ReferenceCountedOpenSslContext.toBIO(ByteBufAllocator.DEFAULT, issuers);
                        if (!SSLContext.setCACertificateBio(ctx, bio)) {
                            String msg = "unable to setup accepted issuers for trustmanager " + manager;
                            final int error = SSL.getLastErrorNumber();
                            if (error != 0) {
                                msg = msg + ". " + SSL.getErrorString((long)error);
                            }
                            throw new SSLException(msg);
                        }
                    }
                    finally {
                        ReferenceCountedOpenSslContext.freeBio(bio);
                    }
                }
                SSLContext.setSniHostnameMatcher(ctx, (SniHostNameMatcher)new OpenSslSniHostnameMatcher(engines));
            }
            catch (final SSLException e2) {
                throw e2;
            }
            catch (final Exception e) {
                throw new SSLException("unable to setup trustmanager", e);
            }
            final OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider);
            sessionContext.setSessionIdContext(ReferenceCountedOpenSslServerContext.ID);
            sessionContext.setSessionCacheEnabled(ReferenceCountedOpenSslServerContext.SERVER_ENABLE_SESSION_CACHE);
            if (sessionCacheSize > 0L) {
                sessionContext.setSessionCacheSize((int)Math.min(sessionCacheSize, 2147483647L));
            }
            if (sessionTimeout > 0L) {
                sessionContext.setSessionTimeout((int)Math.min(sessionTimeout, 2147483647L));
            }
            keyMaterialProvider = null;
            return sessionContext;
        }
        finally {
            if (keyMaterialProvider != null) {
                keyMaterialProvider.destroy();
            }
        }
    }
    
    private static void setVerifyCallback(final long ctx, final Map<Long, ReferenceCountedOpenSslEngine> engines, final X509TrustManager manager) {
        if (ReferenceCountedOpenSslContext.useExtendedTrustManager(manager)) {
            SSLContext.setCertVerifyCallback(ctx, (CertificateVerifier)new ExtendedTrustManagerVerifyCallback(engines, (X509ExtendedTrustManager)manager));
        }
        else {
            SSLContext.setCertVerifyCallback(ctx, (CertificateVerifier)new TrustManagerVerifyCallback(engines, manager));
        }
    }
    
    static {
        logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class);
        ID = new byte[] { 110, 101, 116, 116, 121 };
    }
    
    private static final class OpenSslServerCertificateCallback implements CertificateCallback
    {
        private final Map<Long, ReferenceCountedOpenSslEngine> engines;
        private final OpenSslKeyMaterialManager keyManagerHolder;
        
        OpenSslServerCertificateCallback(final Map<Long, ReferenceCountedOpenSslEngine> engines, final OpenSslKeyMaterialManager keyManagerHolder) {
            this.engines = engines;
            this.keyManagerHolder = keyManagerHolder;
        }
        
        public void handle(final long ssl, final byte[] keyTypeBytes, final byte[][] asn1DerEncodedPrincipals) throws Exception {
            final ReferenceCountedOpenSslEngine engine = this.engines.get(ssl);
            if (engine == null) {
                return;
            }
            try {
                this.keyManagerHolder.setKeyMaterialServerSide(engine);
            }
            catch (final Throwable cause) {
                engine.initHandshakeException(cause);
                if (cause instanceof Exception) {
                    throw (Exception)cause;
                }
                throw new SSLException(cause);
            }
        }
    }
    
    private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier
    {
        private final X509TrustManager manager;
        
        TrustManagerVerifyCallback(final Map<Long, ReferenceCountedOpenSslEngine> engines, final X509TrustManager manager) {
            super(engines);
            this.manager = manager;
        }
        
        @Override
        void verify(final ReferenceCountedOpenSslEngine engine, final X509Certificate[] peerCerts, final String auth) throws Exception {
            this.manager.checkClientTrusted(peerCerts, auth);
        }
    }
    
    private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier
    {
        private final X509ExtendedTrustManager manager;
        
        ExtendedTrustManagerVerifyCallback(final Map<Long, ReferenceCountedOpenSslEngine> engines, final X509ExtendedTrustManager manager) {
            super(engines);
            this.manager = manager;
        }
        
        @Override
        void verify(final ReferenceCountedOpenSslEngine engine, final X509Certificate[] peerCerts, final String auth) throws Exception {
            this.manager.checkClientTrusted(peerCerts, auth, engine);
        }
    }
    
    private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher
    {
        private final Map<Long, ReferenceCountedOpenSslEngine> engines;
        
        OpenSslSniHostnameMatcher(final Map<Long, ReferenceCountedOpenSslEngine> engines) {
            this.engines = engines;
        }
        
        public boolean match(final long ssl, final String hostname) {
            final ReferenceCountedOpenSslEngine engine = this.engines.get(ssl);
            if (engine != null) {
                return engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8));
            }
            ReferenceCountedOpenSslServerContext.logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", (Object)ssl);
            return false;
        }
    }
}
