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.java7;
012
013import org.minidns.dane.DaneVerifier;
014import org.minidns.dane.X509TrustManagerUtil;
015import org.minidns.dnssec.DnssecClient;
016
017import javax.net.ssl.SSLContext;
018import javax.net.ssl.SSLEngine;
019import javax.net.ssl.TrustManager;
020import javax.net.ssl.X509ExtendedTrustManager;
021import javax.net.ssl.X509TrustManager;
022
023import java.net.Socket;
024import java.security.KeyManagementException;
025import java.security.NoSuchAlgorithmException;
026import java.security.cert.CertificateException;
027import java.security.cert.X509Certificate;
028import java.util.logging.Logger;
029
030public class DaneExtendedTrustManager extends X509ExtendedTrustManager {
031    private static final Logger LOGGER = Logger.getLogger(DaneExtendedTrustManager.class.getName());
032
033    private final X509TrustManager base;
034    private final DaneVerifier verifier;
035
036    public static void inject() {
037        inject(new DaneExtendedTrustManager());
038    }
039
040    public static void inject(DaneExtendedTrustManager trustManager) {
041        try {
042            SSLContext sslContext = SSLContext.getInstance("TLS");
043            sslContext.init(null, new TrustManager[] {trustManager}, null);
044            SSLContext.setDefault(sslContext);
045        } catch (NoSuchAlgorithmException | KeyManagementException e) {
046            throw new RuntimeException(e);
047        }
048    }
049
050    public DaneExtendedTrustManager() {
051        this(X509TrustManagerUtil.getDefault());
052    }
053
054    public DaneExtendedTrustManager(DnssecClient client) {
055        this(client, X509TrustManagerUtil.getDefault());
056    }
057
058    public DaneExtendedTrustManager(X509TrustManager base) {
059        this(new DaneVerifier(), base);
060    }
061
062    public DaneExtendedTrustManager(DnssecClient client, X509TrustManager base) {
063        this(new DaneVerifier(client), base);
064    }
065
066    public DaneExtendedTrustManager(DaneVerifier verifier, X509TrustManager base) {
067        this.verifier = verifier;
068        this.base = base;
069    }
070
071    @Override
072    public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
073        if (base == null) {
074            LOGGER.warning("DaneExtendedTrustManager invalidly used for client certificate check and no fallback X509TrustManager specified");
075        } else {
076            LOGGER.info("DaneExtendedTrustManager invalidly used for client certificate check forwarding request to fallback X509TrustManage");
077            if (base instanceof X509ExtendedTrustManager) {
078                ((X509ExtendedTrustManager) base).checkClientTrusted(chain, authType, socket);
079            } else {
080                base.checkClientTrusted(chain, authType);
081            }
082        }
083    }
084
085    @Override
086    public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
087        if (!verifier.verifyCertificateChain(chain, socket.getInetAddress().getHostName(), socket.getPort())) {
088            if (base instanceof X509ExtendedTrustManager) {
089                ((X509ExtendedTrustManager) base).checkServerTrusted(chain, authType, socket);
090            } else {
091                base.checkClientTrusted(chain, authType);
092            }
093        }
094    }
095
096    @Override
097    public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException {
098        if (base == null) {
099            LOGGER.warning("DaneExtendedTrustManager invalidly used for client certificate check and no fallback X509TrustManager specified");
100        } else {
101            LOGGER.info("DaneExtendedTrustManager invalidly used for client certificate check, forwarding request to fallback X509TrustManage");
102            if (base instanceof X509ExtendedTrustManager) {
103                ((X509ExtendedTrustManager) base).checkClientTrusted(chain, authType, engine);
104            } else {
105                base.checkClientTrusted(chain, authType);
106            }
107        }
108    }
109
110    @Override
111    public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException {
112        if (!verifier.verifyCertificateChain(chain, engine.getPeerHost(), engine.getPeerPort())) {
113            if (base instanceof X509ExtendedTrustManager) {
114                ((X509ExtendedTrustManager) base).checkServerTrusted(chain, authType, engine);
115            } else {
116                base.checkClientTrusted(chain, authType);
117            }
118        }
119    }
120
121    @Override
122    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
123        if (base == null) {
124            LOGGER.warning("DaneExtendedTrustManager invalidly used for client certificate check and no fallback X509TrustManager specified");
125        } else {
126            LOGGER.info("DaneExtendedTrustManager invalidly used for client certificate check, forwarding request to fallback X509TrustManage");
127            base.checkClientTrusted(chain, authType);
128        }
129    }
130
131    @Override
132    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
133        LOGGER.info("DaneExtendedTrustManager cannot be used without hostname information, forwarding request to fallback X509TrustManage");
134        base.checkServerTrusted(chain, authType);
135    }
136
137    @Override
138    public X509Certificate[] getAcceptedIssuers() {
139        return base.getAcceptedIssuers();
140    }
141}