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

package io.netty.handler.ssl;

import java.net.Socket;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.Certificate;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.TrustManager;
import java.util.Map;
import java.util.Collections;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLEngine;
import java.util.Set;

final class ResumptionController
{
    private final Set<SSLEngine> confirmedValidations;
    private final AtomicReference<ResumableX509ExtendedTrustManager> resumableTm;
    
    ResumptionController() {
        this.confirmedValidations = Collections.synchronizedSet((Set<SSLEngine>)Collections.newSetFromMap((Map<T, Boolean>)new WeakHashMap<Object, Boolean>()));
        this.resumableTm = new AtomicReference<ResumableX509ExtendedTrustManager>();
    }
    
    public TrustManager wrapIfNeeded(final TrustManager tm) {
        if (!(tm instanceof ResumableX509ExtendedTrustManager)) {
            return tm;
        }
        if (!(tm instanceof X509ExtendedTrustManager)) {
            throw new IllegalStateException("ResumableX509ExtendedTrustManager implementation must be a subclass of X509ExtendedTrustManager, found: " + ((tm == null) ? null : tm.getClass()));
        }
        if (!this.resumableTm.compareAndSet(null, (ResumableX509ExtendedTrustManager)tm)) {
            throw new IllegalStateException("Only one ResumableX509ExtendedTrustManager can be configured for resumed sessions");
        }
        return new X509ExtendedWrapTrustManager((X509ExtendedTrustManager)tm, this.confirmedValidations);
    }
    
    public void remove(final SSLEngine engine) {
        if (this.resumableTm.get() != null) {
            this.confirmedValidations.remove(unwrapEngine(engine));
        }
    }
    
    public boolean validateResumeIfNeeded(SSLEngine engine) throws CertificateException, SSLPeerUnverifiedException {
        final SSLSession session = engine.getSession();
        final boolean valid = session.isValid();
        final ResumableX509ExtendedTrustManager tm;
        if (valid && (engine.getUseClientMode() || engine.getNeedClientAuth() || engine.getWantClientAuth()) && (tm = this.resumableTm.get()) != null) {
            engine = unwrapEngine(engine);
            if (!this.confirmedValidations.remove(engine)) {
                Certificate[] peerCertificates;
                try {
                    peerCertificates = session.getPeerCertificates();
                }
                catch (final SSLPeerUnverifiedException e) {
                    if (engine.getUseClientMode() || engine.getNeedClientAuth()) {
                        throw e;
                    }
                    return false;
                }
                if (engine.getUseClientMode()) {
                    tm.resumeServerTrusted(chainOf(peerCertificates), engine);
                }
                else {
                    tm.resumeClientTrusted(chainOf(peerCertificates), engine);
                }
                return true;
            }
        }
        return false;
    }
    
    private static SSLEngine unwrapEngine(final SSLEngine engine) {
        if (engine instanceof JdkSslEngine) {
            return ((JdkSslEngine)engine).getWrappedEngine();
        }
        return engine;
    }
    
    private static X509Certificate[] chainOf(final Certificate[] peerCertificates) {
        if (peerCertificates instanceof X509Certificate[]) {
            return (X509Certificate[])peerCertificates;
        }
        final X509Certificate[] chain = new X509Certificate[peerCertificates.length];
        for (int i = 0; i < peerCertificates.length; ++i) {
            final Certificate cert = peerCertificates[i];
            if (!(cert instanceof X509Certificate) && cert != null) {
                throw new IllegalArgumentException("Only X509Certificates are supported, found: " + cert.getClass());
            }
            chain[i] = (X509Certificate)cert;
        }
        return chain;
    }
    
    private static final class X509ExtendedWrapTrustManager extends X509ExtendedTrustManager
    {
        private final X509ExtendedTrustManager trustManager;
        private final Set<SSLEngine> confirmedValidations;
        
        X509ExtendedWrapTrustManager(final X509ExtendedTrustManager trustManager, final Set<SSLEngine> confirmedValidations) {
            this.trustManager = trustManager;
            this.confirmedValidations = confirmedValidations;
        }
        
        private static void unsupported() throws CertificateException {
            throw new CertificateException(new UnsupportedOperationException("Resumable trust managers require the SSLEngine parameter"));
        }
        
        @Override
        public void checkClientTrusted(final X509Certificate[] chain, final String authType, final Socket socket) throws CertificateException {
            unsupported();
        }
        
        @Override
        public void checkServerTrusted(final X509Certificate[] chain, final String authType, final Socket socket) throws CertificateException {
            unsupported();
        }
        
        @Override
        public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
            unsupported();
        }
        
        @Override
        public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
            unsupported();
        }
        
        @Override
        public void checkClientTrusted(final X509Certificate[] chain, final String authType, final SSLEngine engine) throws CertificateException {
            this.trustManager.checkClientTrusted(chain, authType, engine);
            this.confirmedValidations.add(engine);
        }
        
        @Override
        public void checkServerTrusted(final X509Certificate[] chain, final String authType, final SSLEngine engine) throws CertificateException {
            this.trustManager.checkServerTrusted(chain, authType, engine);
            this.confirmedValidations.add(engine);
        }
        
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return this.trustManager.getAcceptedIssuers();
        }
    }
}
