org.eclipse.californium.elements.tcp.TlsContextUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.californium.elements.tcp.TlsContextUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2016, 2017 Bosch Software Innovations GmbH and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 * 
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 *    http://www.eclipse.org/org/documents/edl-v10.html.
 * 
 * Contributors:
 *    Bosch Software Innovations GmbH - initial implementation.
 *                                      Derived from NettyContextUtils.
 *    Achim Kraus (Bosch Software Innovations GmbH) - remove spaces from session id.
 ******************************************************************************/
package org.eclipse.californium.elements.tcp;

import java.net.InetSocketAddress;
import java.security.Principal;
import java.security.cert.Certificate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;

import org.eclipse.californium.elements.auth.X509CertPath;
import org.eclipse.californium.elements.EndpointContext;
import org.eclipse.californium.elements.TlsEndpointContext;
import org.eclipse.californium.elements.util.StringUtil;

import io.netty.channel.Channel;
import io.netty.handler.ssl.SslHandler;

/**
 * Util for building for TLS endpoint context from channel.
 */
public class TlsContextUtil extends TcpContextUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(TlsContextUtil.class.getName());

    /**
     * Log warn messages, if remote peer's principal is not valid.
     */
    private final boolean warnMissingPrincipal;

    /**
     * Create utility instance.
     * 
     * @param warnMissingPrincipal {@code true}, to log warn messages, if remote
     *            peer's principal is not valid. {@code false}, to log trace
     *            messages.
     */
    public TlsContextUtil(boolean warnMissingPrincipal) {
        this.warnMissingPrincipal = warnMissingPrincipal;
    }

    /**
     * Build endpoint context related to the provided channel.
     * 
     * @param channel channel of endpoint context
     * @return endpoint context
     * @throws IllegalStateException if no {@link SslHandler} is available or
     *             the handshake isn't finished yet.
     */
    @Override
    public EndpointContext buildEndpointContext(Channel channel) {
        InetSocketAddress address = (InetSocketAddress) channel.remoteAddress();
        String id = channel.id().asShortText();
        SslHandler sslHandler = channel.pipeline().get(SslHandler.class);
        if (sslHandler == null) {
            throw new IllegalStateException("Missing SslHandler for " + id + "!");
        }
        SSLEngine sslEngine = sslHandler.engine();
        SSLSession sslSession = sslEngine.getSession();
        if (sslSession != null) {
            boolean checkKerberos = false;
            Principal principal = null;
            try {
                Certificate[] peerCertificateChain = sslSession.getPeerCertificates();
                if (peerCertificateChain != null && peerCertificateChain.length != 0) {
                    principal = X509CertPath.fromCertificatesChain(peerCertificateChain);
                } else {
                    // maybe kerberos is used and therefore
                    // getPeerCertificates fails
                    checkKerberos = true;
                }
            } catch (SSLPeerUnverifiedException e1) {
                // maybe kerberos is used and therefore
                // getPeerCertificates fails
                checkKerberos = true;
            } catch (RuntimeException e) {
                LOGGER.warn("TLS({}) failed to extract principal {}", id, e.getMessage());
            }

            if (checkKerberos) {
                try {
                    principal = sslSession.getPeerPrincipal();
                } catch (SSLPeerUnverifiedException e2) {
                    // still unverified, so also no kerberos
                    if (warnMissingPrincipal) {
                        LOGGER.warn("TLS({}) failed to verify principal, {}", id, e2.getMessage());
                    } else {
                        LOGGER.trace("TLS({}) failed to verify principal, {}", id, e2.getMessage());
                    }
                }
            }

            if (principal != null) {
                LOGGER.debug("TLS({}) Principal {}", id, principal.getName());
            } else if (warnMissingPrincipal) {
                LOGGER.warn("TLS({}) principal missing", id);
            } else {
                LOGGER.trace("TLS({}) principal missing", id);
            }

            byte[] sessionId = sslSession.getId();
            if (sessionId != null && sessionId.length > 0) {
                String sslId = StringUtil.byteArray2HexString(sessionId, StringUtil.NO_SEPARATOR, 0);
                String cipherSuite = sslSession.getCipherSuite();
                LOGGER.debug("TLS({},{},{})", id, StringUtil.trunc(sslId, 14), cipherSuite);
                return new TlsEndpointContext(address, principal, id, sslId, cipherSuite);
            }
        }
        // TLS handshake not finished
        throw new IllegalStateException("TLS handshake " + id + " not ready!");
    }
}