All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sleepycat.je.rep.utilint.net.SSLMirrorMatcher Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */

package com.sleepycat.je.rep.utilint.net;

import static java.util.logging.Level.INFO;

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.Principal;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.security.auth.x500.X500Principal;

import com.sleepycat.je.rep.ReplicationSSLConfig;
import com.sleepycat.je.rep.net.InstanceContext;
import com.sleepycat.je.rep.net.InstanceLogger;
import com.sleepycat.je.rep.net.InstanceParams;

/**
 * Common base class for mirror comparisons.  Supports both authenticator and
 * host verifier implementations.
 */

class SSLMirrorMatcher {

    /*
     * The Principal that represents us when in the expected peer's ssl mode.
     */
    final private Principal ourPrincipal;
    final private InstanceLogger logger;

    /**
     * Construct an SSLMirrorMatcher
     *
     * @param params The instantiation parameters.
     * @param clientMode set to true if the matcher will be evaluated
     * as a client that has a server as a peer, or false if it will be
     * evaluated as a server that has received a connection from a client.
     * @throws IllegalArgumentException if the instance cannot be created due
     * to a problem related to the input parameters
     */
    public SSLMirrorMatcher(InstanceParams params, boolean clientMode)
        throws IllegalArgumentException {

        ourPrincipal = determinePrincipal(params.getContext(), clientMode);
        if (ourPrincipal == null) {
            throw new IllegalArgumentException(
                "Unable to determine a local principal for comparison " +
                "with peer principals");
        }
        logger = params.getContext().getLoggerFactory().getLogger(getClass());
    }

    /**
     * Checks whether the SSL session peer's certificate DN matches our own.
     *
     * @param sslSession the SSL session that has been established with a peer
     * @return true if the peer's certificate DN matches ours
     */
    public boolean peerMatches(SSLSession sslSession) {

        if (ourPrincipal == null) {
            return false;
        }

        /*
         * Get the peer principal, which should also be an X500Principal.
         * We validate that here.
         */
        Principal peerPrincipal = null;
        try {
            peerPrincipal = sslSession.getPeerPrincipal();
        } catch (SSLPeerUnverifiedException pue) {
            return false;
        }

        if (peerPrincipal == null ||
            ! (peerPrincipal instanceof X500Principal)) {
            logger.log(
                INFO,
                "Unable to attempt peer validation - peer Principal is: " +
                peerPrincipal);
            return false;
        }

        return ourPrincipal.equals(peerPrincipal);
    }

    /**
     * Attempt to determine the Principal that we take on when connecting
     * in client or server context based on the ReplicationNetworkConfig.
     * If we are unable to determine that principal, return null.
     */
    private Principal determinePrincipal(
        InstanceContext context, boolean clientMode)
        throws IllegalArgumentException {

        final ReplicationSSLConfig config =
            (ReplicationSSLConfig) context.getRepNetConfig();

        /*
         * Determine what alias would be used.  It is allowable for this to be
         * null.
         */
        String aliasProp = clientMode ?
            config.getSSLClientKeyAlias() :
            config.getSSLServerKeyAlias();

        final KeyStore keyStore = SSLChannelFactory.readKeyStore(context);

        if (aliasProp == null || aliasProp.isEmpty()) {
            /* Since we weren't told which one to use, there better be
             * only one option, or this might behave unexpectedly. */
            try {
                if (keyStore.size() < 1) {
                    logger.log(INFO, "KeyStore is empty");
                    return null;
                } else if (keyStore.size() > 1) {
                    logger.log(INFO, "KeyStore has multiple entries but no " +
                               "alias was specified.  Using the first one " +
                               "available.");
                }
                final Enumeration e = keyStore.aliases();
                aliasProp = e.nextElement();
            } catch (KeyStoreException kse) {
                throw new IllegalArgumentException(
                    "Error accessing aliases from the keystore", kse);
            }
        }

        Certificate cert = null;
        try {
            cert = keyStore.getCertificate(aliasProp);
        } catch (KeyStoreException kse) {
            /* Shouldn't be possible */
            throw new IllegalArgumentException(
                "Error accessing certificate with alias " + aliasProp +
                " from the keystore", kse);
        }

        if (cert == null) {
            logger.log(INFO, "No certificate for alias " + aliasProp +
                       " found in KeyStore");
            throw new IllegalArgumentException(
                "Unable to find a certificate in the keystore");
        }

        if (!(cert instanceof X509Certificate)) {
            logger.log(INFO, "The certificate for alias " + aliasProp +
                       " is not an X509Certificate.");
            throw new IllegalArgumentException(
                "Unable to find a valid certificate in the keystore");
        }

        final X509Certificate x509Cert = (X509Certificate) cert;
        return x509Cert.getSubjectX500Principal();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy