/* * 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-end-point" channel binding strategy used by various types * of authentication mechanisms. * * @author David M. Lloyd */ public final class TLSServerEndPointChannelBinding { public static final String TLS_SERVER_ENDPOINT = "tls-server-end-point"; 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-end-point try { final byte[] bindingData = getChannelBindingData(serverCerts[0]); if (bindingData != null) { channelBindingCallback.setBindingData(bindingData); channelBindingCallback.setBindingType(TLS_SERVER_ENDPOINT); return; } } catch (CertificateEncodingException | NoSuchAlgorithmException e) { // fail silently } } CallbackUtil.unsupported(channelBindingCallback); } static byte[] getChannelBindingData(X509Certificate serverCert) throws NoSuchAlgorithmException, CertificateEncodingException { if (serverCert == null) { return null; } final String digestAlgorithm = TLSServerEndPointChannelBinding.getDigestAlgorithm(serverCert.getSigAlgOID()); if (digestAlgorithm == null) { return null; } return MessageDigest.getInstance(digestAlgorithm).digest(serverCert.getEncoded()); } }