001/*
002 * JPPF.
003 * Copyright (C) 2005-2018 JPPF Team.
004 * http://www.jppf.org
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.jppf.ssl;
020
021import java.security.cert.*;
022import java.util.*;
023
024import javax.net.ssl.X509TrustManager;
025
026/**
027 * Instances of this class allow an SSLSocketFactory or an SSLEngine to perform checks against multiple trust managers from multiple trusstores.
028 * @author Laurent Cohen
029 * @since 6.0
030 */
031public class CompositeX509TrustManager implements X509TrustManager {
032  /**
033   * The list of key managers to handle.
034   */
035  private final List<X509TrustManager> trustManagers;
036
037  /**
038   * Creates a new {@link CompositeX509TrustManager}.
039   * @param trustManagers the X509 trust managers, ordered with the most-preferred managers first.
040   */
041  public CompositeX509TrustManager(final List<X509TrustManager> trustManagers) {
042    this.trustManagers = Collections.unmodifiableList(new ArrayList<>(trustManagers));
043  }
044
045  @Override
046  public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
047    for (X509TrustManager mgr: trustManagers) {
048      try {
049        mgr.checkClientTrusted(chain, authType);
050        return;
051      } catch (@SuppressWarnings("unused") final Exception e) {
052      }
053    }
054    throw new CertificateException(String.format("client not trusted for chain = %s, authType = %s, accepted issuers = %s", Arrays.asList(chain), authType, Arrays.asList(getAcceptedIssuers())));
055  }
056
057  @Override
058  public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
059    for (X509TrustManager mgr: trustManagers) {
060      try {
061        mgr.checkServerTrusted(chain, authType);
062        return;
063      } catch (@SuppressWarnings("unused") final Exception e) {
064      }
065    }
066    throw new CertificateException(String.format("server not trusted for chain = %s, authType = %s, accepted issuers = %s", Arrays.asList(chain), authType, Arrays.asList(getAcceptedIssuers())));
067  }
068
069  @Override
070  public X509Certificate[] getAcceptedIssuers() {
071    final List<X509Certificate> issuers = new ArrayList<>();
072    for (final X509TrustManager mgr: trustManagers) {
073      for (final X509Certificate cert: mgr.getAcceptedIssuers()) issuers.add(cert);
074    }
075    return issuers.toArray(new X509Certificate[issuers.size()]);
076  }
077}