/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2017 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.wildfly.security.ssl;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;

import javax.security.auth.callback.UnsupportedCallbackException;

import org.wildfly.security.asn1.ASN1;
import org.wildfly.security.auth.callback.CallbackUtil;
import org.wildfly.security.auth.callback.ChannelBindingCallback;

/**
 * Utilities for handling the "tls-server-endpoint" channel binding strategy used by various types
 * of authentication mechanisms.
 *
 * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
 */
public final class TLSServerEndPointChannelBinding {
    public static final String TLS_SERVER_ENDPOINT = "tls-server-endpoint";

    private TLSServerEndPointChannelBinding() {}

    /**
     * Get the digest algorithm that would be used for a given signature algorithm OID.
     *
     * @param sigAlgOID the signature algorithm OID (must not be {@code null})
     * @return the digest algorithm, or {@code null} if the OID is not recognized
     */
    public static String getDigestAlgorithm(final String sigAlgOID) {
        switch (sigAlgOID) {
            case ASN1.OID_MD2:
            case ASN1.OID_MD2_WITH_RSA:
            case ASN1.OID_MD4_WITH_RSA:
            case ASN1.OID_MD5:
            case ASN1.OID_MD5_WITH_RSA:
            case ASN1.OID_SHA1_WITH_DSA:
            case ASN1.OID_SHA1_WITH_RSA:
            case ASN1.OID_SHA1_WITH_ECDSA:
            case ASN1.OID_SHA1:
            case ASN1.OID_SHA224_WITH_ECDSA:
            case ASN1.OID_SHA256_WITH_RSA:
            case ASN1.OID_SHA256_WITH_ECDSA:
                return "SHA-256";
            case ASN1.OID_SHA384_WITH_ECDSA:
            case ASN1.OID_SHA384_WITH_RSA:
                return "SHA-384";
            case ASN1.OID_SHA512_WITH_ECDSA:
            case ASN1.OID_SHA512_WITH_RSA:
                return "SHA-512";
            default: {
                return null;
            }
        }
    }

    /**
     * Convenience method to handle a channel binding callback.
     *
     * @param channelBindingCallback the callback (must not be {@code null})
     * @param serverCerts the server certificate chain
     * @throws UnsupportedCallbackException if the server certificates are not present or unsupported and the callback is not optional
     */
    public static void handleChannelBindingCallback(ChannelBindingCallback channelBindingCallback, X509Certificate[] serverCerts) throws UnsupportedCallbackException {
        if (serverCerts != null && serverCerts.length > 0) {
            // tls-server-endpoint
            final X509Certificate serverCert = serverCerts[0];
            final String digestAlgorithm = TLSServerEndPointChannelBinding.getDigestAlgorithm(serverCert.getSigAlgOID());
            if (digestAlgorithm != null) try {
                final MessageDigest messageDigest = MessageDigest.getInstance(digestAlgorithm);
                channelBindingCallback.setBindingData(messageDigest.digest(serverCert.getEncoded()));
                channelBindingCallback.setBindingType(TLS_SERVER_ENDPOINT);
            } catch (CertificateEncodingException | NoSuchAlgorithmException e) {
                // fail silently
            }
        }
        CallbackUtil.unsupported(channelBindingCallback);
    }
}

@@ -1193,24 +1193,25 @@
 s-server-end
+-
 point%22 chann
@@ -1479,24 +1479,25 @@
 s-server-end
+-
 point%22;%0A%0A   
@@ -3359,16 +3359,17 @@
 rver-end
+-
 point%0A  

Rename the "tls-server-endpoint" channel binding type to "tls-server-end-point" to match the IANA channel binding type registry