001/*
002 * Copyright 2015-2020 the original author or authors
003 *
004 * This software is licensed under the Apache License, Version 2.0,
005 * the GNU Lesser General Public License version 2 or later ("LGPL")
006 * and the WTFPL.
007 * You may choose either license to govern your use of this software only
008 * upon the condition that you accept all of the terms of either
009 * the Apache License 2.0, the LGPL 2.1+ or the WTFPL.
010 */
011package org.minidns.dane;
012
013import javax.net.ssl.TrustManager;
014import javax.net.ssl.TrustManagerFactory;
015import javax.net.ssl.X509TrustManager;
016import java.security.KeyStore;
017import java.security.KeyStoreException;
018import java.security.NoSuchAlgorithmException;
019import java.security.cert.CertificateException;
020import java.security.cert.X509Certificate;
021
022public class ExpectingTrustManager implements X509TrustManager {
023    private CertificateException exception;
024    private final X509TrustManager trustManager;
025
026    /**
027     * Creates a new instance of ExpectingTrustManager.
028     *
029     * @param trustManager The {@link X509TrustManager} to be used for verification.
030     *                     {@code null} to use the system default.
031     */
032    public ExpectingTrustManager(X509TrustManager trustManager) {
033        this.trustManager = trustManager == null ? getDefaultTrustManager() : trustManager;
034    }
035
036    public boolean hasException() {
037        return exception != null;
038    }
039
040    public CertificateException getException() {
041        CertificateException e = exception;
042        exception = null;
043        return e;
044    }
045
046    @Override
047    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
048        try {
049            trustManager.checkClientTrusted(chain, authType);
050        } catch (CertificateException e) {
051            exception = e;
052        }
053    }
054
055    @Override
056    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
057        try {
058            trustManager.checkServerTrusted(chain, authType);
059        } catch (CertificateException e) {
060            exception = e;
061        }
062    }
063
064    @Override
065    public X509Certificate[] getAcceptedIssuers() {
066        return trustManager.getAcceptedIssuers();
067    }
068
069    private static X509TrustManager getDefaultTrustManager() {
070        try {
071            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
072            tmf.init((KeyStore) null);
073            for (TrustManager trustManager : tmf.getTrustManagers()) {
074                if (trustManager instanceof X509TrustManager)
075                    return (X509TrustManager) trustManager;
076            }
077        } catch (NoSuchAlgorithmException | KeyStoreException e) {
078            throw new RuntimeException("X.509 not supported.", e);
079        }
080        return null;
081    }
082}