org.wildfly.security.ssl.SSLConnection Maven / Gradle / Ivy
The newest version!
/*
* 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 static org.wildfly.security.ssl.TLSServerEndPointChannelBinding.*;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import org.wildfly.common.Assert;
import org.wildfly.security.auth.callback.ChannelBindingCallback;
/**
* An SSL connection of some sort.
*
* @author David M. Lloyd
*/
public abstract class SSLConnection {
SSLConnection() {
}
/**
* Get the SSL session associated with this connection.
*
* @return the SSL session associated with this connection, or {@code null} if there is none
*/
public abstract SSLSession getSession();
/**
* Get the client-mode flag for this connection.
*
* @return the client-mode flag for this connection
*/
public abstract boolean isClientMode();
/**
* Get the channel binding of the given type from this connection. If the data is not present or the type is not
* supported, {@code null} is returned.
*
* @return the channel binding of the given type from this connection, or {@code null} if it is not supported
*/
public byte[] getChannelBinding(String bindingType) {
// in JDK 10 and later (presumably), this method will be made abstract and the concrete impls will delegate directly to JSSE
final boolean clientMode = isClientMode();
switch (bindingType) {
case TLS_SERVER_ENDPOINT: {
final X509Certificate serverCert;
final SSLSession session = getSession();
if (session == null) {
return null;
}
if (clientMode) {
Certificate[] peerCertificates;
try {
peerCertificates = session.getPeerCertificates();
} catch (SSLPeerUnverifiedException e) {
peerCertificates = null;
}
serverCert = peerCertificates != null && peerCertificates.length > 0 ? (X509Certificate) peerCertificates[0] : null;
} else {
final Certificate[] localCertificates = session.getLocalCertificates();
serverCert = localCertificates != null && localCertificates.length > 0 ? (X509Certificate) localCertificates[0] : null;
}
try {
return getChannelBindingData(serverCert);
} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
return null;
}
}
default: {
return null;
}
}
}
/**
* Populate the given channel binding callback with any channel binding data that might be present on this
* connection. If no channel binding seems to be supported, then the callback will be left unpopulated.
*
* @param callback the binding callback to populate (must not be {@code null})
*/
public void handleChannelBindingCallback(final ChannelBindingCallback callback) {
Assert.checkNotNullParam("callback", callback);
byte[] bindingData = getChannelBinding("tls-unique");
if (bindingData != null) {
callback.setBindingType("tls-unique");
callback.setBindingData(bindingData);
} else {
bindingData = getChannelBinding(TLS_SERVER_ENDPOINT);
if (bindingData != null) {
callback.setBindingType(TLS_SERVER_ENDPOINT);
callback.setBindingData(bindingData);
}
}
}
/**
* Create a {@code SSLConnection} for the given SSL engine.
*
* @param engine the SSL engine (must not be {@code null})
* @return the SSL connection (not {@code null})
*/
public static SSLConnection forEngine(SSLEngine engine) {
Assert.checkNotNullParam("engine", engine);
return new SSLConnection() {
public SSLSession getSession() {
return engine.getSession();
}
public boolean isClientMode() {
return engine.getUseClientMode();
}
};
}
/**
* Create a {@code SSLConnection} for the given SSL socket.
*
* @param socket the SSL socket (must not be {@code null})
* @return the SSL connection (not {@code null})
*/
public static SSLConnection forSocket(SSLSocket socket) {
Assert.checkNotNullParam("socket", socket);
return new SSLConnection() {
public SSLSession getSession() {
return socket.getSession();
}
public boolean isClientMode() {
return socket.getUseClientMode();
}
};
}
/**
* Create a {@code SSLConnection} for the given SSL socket. Since no connection information will be
* available in this case, not all channel binding modes will be supported.
*
* @param session the SSL session (must not be {@code null})
* @param clientMode {@code true} if the session is client-side, {@code false} if it is server-side
* @return the SSL connection (not {@code null})
*/
public static SSLConnection forSession(SSLSession session, boolean clientMode) {
Assert.checkNotNullParam("session", session);
return new SSLConnection() {
public SSLSession getSession() {
return session;
}
public boolean isClientMode() {
return clientMode;
}
};
}
}