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

package io.netty.handler.ssl;

import javax.net.ssl.X509KeyManager;
import java.net.Socket;
import javax.net.ssl.SSLEngine;
import java.security.Principal;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.security.auth.x500.X500Principal;
import javax.net.ssl.SSLException;
import java.util.Arrays;
import javax.net.ssl.SSLHandshakeException;

final class OpenSslKeyMaterialManager
{
    static final String KEY_TYPE_RSA = "RSA";
    static final String KEY_TYPE_DH_RSA = "DH_RSA";
    static final String KEY_TYPE_EC = "EC";
    static final String KEY_TYPE_EC_EC = "EC_EC";
    static final String KEY_TYPE_EC_RSA = "EC_RSA";
    private static final int TYPE_RSA = 1;
    private static final int TYPE_DH_RSA = 2;
    private static final int TYPE_EC = 4;
    private static final int TYPE_EC_EC = 8;
    private static final int TYPE_EC_RSA = 16;
    private final OpenSslKeyMaterialProvider provider;
    private final boolean hasTmpDhKeys;
    
    OpenSslKeyMaterialManager(final OpenSslKeyMaterialProvider provider, final boolean hasTmpDhKeys) {
        this.provider = provider;
        this.hasTmpDhKeys = hasTmpDhKeys;
    }
    
    void setKeyMaterialServerSide(final ReferenceCountedOpenSslEngine engine) throws SSLException {
        final String[] authMethods = engine.authMethods();
        if (authMethods.length == 0) {
            throw new SSLHandshakeException("Unable to find key material");
        }
        int seenTypes = 0;
        for (final String authMethod : authMethods) {
            final int typeBit = resolveKeyTypeBit(authMethod);
            if (typeBit != 0) {
                if ((seenTypes & typeBit) == 0x0) {
                    seenTypes |= typeBit;
                    final String keyType = keyTypeString(typeBit);
                    final String alias = this.chooseServerAlias(engine, keyType);
                    if (alias != null) {
                        this.setKeyMaterial(engine, alias);
                        return;
                    }
                }
            }
        }
        if (this.hasTmpDhKeys && authMethods.length == 1 && ("DH_anon".equals(authMethods[0]) || "ECDH_anon".equals(authMethods[0]))) {
            return;
        }
        throw new SSLHandshakeException("Unable to find key material for auth method(s): " + Arrays.toString(authMethods));
    }
    
    private static int resolveKeyTypeBit(final String authMethod) {
        switch (authMethod) {
            case "RSA":
            case "DHE_RSA":
            case "ECDHE_RSA": {
                return 1;
            }
            case "DH_RSA": {
                return 2;
            }
            case "ECDHE_ECDSA": {
                return 4;
            }
            case "ECDH_ECDSA": {
                return 8;
            }
            case "ECDH_RSA": {
                return 16;
            }
            default: {
                return 0;
            }
        }
    }
    
    private static String keyTypeString(final int typeBit) {
        switch (typeBit) {
            case 1: {
                return "RSA";
            }
            case 2: {
                return "DH_RSA";
            }
            case 4: {
                return "EC";
            }
            case 8: {
                return "EC_EC";
            }
            case 16: {
                return "EC_RSA";
            }
            default: {
                return null;
            }
        }
    }
    
    void setKeyMaterialClientSide(final ReferenceCountedOpenSslEngine engine, final String[] keyTypes, final X500Principal[] issuer) throws SSLException {
        final String alias = this.chooseClientAlias(engine, keyTypes, issuer);
        if (alias != null) {
            this.setKeyMaterial(engine, alias);
        }
    }
    
    private void setKeyMaterial(final ReferenceCountedOpenSslEngine engine, final String alias) throws SSLException {
        OpenSslKeyMaterial keyMaterial = null;
        try {
            keyMaterial = this.provider.chooseKeyMaterial(engine.alloc, alias);
            if (keyMaterial == null) {
                return;
            }
            engine.setKeyMaterial(keyMaterial);
        }
        catch (final SSLException e) {
            throw e;
        }
        catch (final Exception e2) {
            throw new SSLException(e2);
        }
        finally {
            if (keyMaterial != null) {
                keyMaterial.release();
            }
        }
    }
    
    private String chooseClientAlias(final ReferenceCountedOpenSslEngine engine, final String[] keyTypes, final X500Principal[] issuer) {
        final X509KeyManager manager = this.provider.keyManager();
        if (manager instanceof X509ExtendedKeyManager) {
            return ((X509ExtendedKeyManager)manager).chooseEngineClientAlias(keyTypes, issuer, engine);
        }
        return manager.chooseClientAlias(keyTypes, issuer, null);
    }
    
    private String chooseServerAlias(final ReferenceCountedOpenSslEngine engine, final String type) {
        final X509KeyManager manager = this.provider.keyManager();
        if (manager instanceof X509ExtendedKeyManager) {
            return ((X509ExtendedKeyManager)manager).chooseEngineServerAlias(type, null, engine);
        }
        return manager.chooseServerAlias(type, null, null);
    }
}
