001/* 002 * Copyright 2015-2024 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; 016import org.minidns.util.InetAddressUtil; 017 018import javax.net.ssl.SSLContext; 019import javax.net.ssl.SSLEngine; 020import javax.net.ssl.SSLSocket; 021import javax.net.ssl.TrustManager; 022import javax.net.ssl.X509ExtendedTrustManager; 023import javax.net.ssl.X509TrustManager; 024 025import java.net.Socket; 026import java.security.KeyManagementException; 027import java.security.NoSuchAlgorithmException; 028import java.security.cert.CertificateException; 029import java.security.cert.X509Certificate; 030import java.util.logging.Logger; 031 032public class DaneExtendedTrustManager extends X509ExtendedTrustManager { 033 private static final Logger LOGGER = Logger.getLogger(DaneExtendedTrustManager.class.getName()); 034 035 private final X509TrustManager base; 036 private final DaneVerifier verifier; 037 038 public static void inject() { 039 inject(new DaneExtendedTrustManager()); 040 } 041 042 public static void inject(DaneExtendedTrustManager trustManager) { 043 try { 044 SSLContext sslContext = SSLContext.getInstance("TLS"); 045 sslContext.init(null, new TrustManager[] {trustManager}, null); 046 SSLContext.setDefault(sslContext); 047 } catch (NoSuchAlgorithmException | KeyManagementException e) { 048 throw new RuntimeException(e); 049 } 050 } 051 052 public DaneExtendedTrustManager() { 053 this(X509TrustManagerUtil.getDefault()); 054 } 055 056 public DaneExtendedTrustManager(DnssecClient client) { 057 this(client, X509TrustManagerUtil.getDefault()); 058 } 059 060 public DaneExtendedTrustManager(X509TrustManager base) { 061 this(new DaneVerifier(), base); 062 } 063 064 public DaneExtendedTrustManager(DnssecClient client, X509TrustManager base) { 065 this(new DaneVerifier(client), base); 066 } 067 068 public DaneExtendedTrustManager(DaneVerifier verifier, X509TrustManager base) { 069 this.verifier = verifier; 070 this.base = base; 071 } 072 073 @Override 074 public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { 075 if (base == null) { 076 LOGGER.warning("DaneExtendedTrustManager invalidly used for client certificate check and no fallback X509TrustManager specified"); 077 return; 078 } 079 080 LOGGER.info("DaneExtendedTrustManager invalidly used for client certificate check forwarding request to fallback X509TrustManage"); 081 if (base instanceof X509ExtendedTrustManager) { 082 ((X509ExtendedTrustManager) base).checkClientTrusted(chain, authType, socket); 083 } else { 084 base.checkClientTrusted(chain, authType); 085 } 086 } 087 088 @Override 089 public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { 090 boolean verificationSuccessful = false; 091 092 if (socket instanceof SSLSocket) { 093 final SSLSocket sslSocket = (SSLSocket) socket; 094 final String hostname = sslSocket.getHandshakeSession().getPeerHost(); 095 096 if (hostname == null) { 097 LOGGER.warning("Hostname returned by sslSocket.getHandshakeSession().getPeerHost() is null"); 098 } else if (InetAddressUtil.isIpAddress(hostname)) { 099 LOGGER.warning( 100 "Hostname returned by sslSocket.getHandshakeSession().getPeerHost() '" + hostname 101 + "' is an IP address"); 102 } else { 103 final int port = socket.getPort(); 104 verificationSuccessful = verifier.verifyCertificateChain(chain, hostname, port); 105 } 106 } else { 107 throw new IllegalStateException("The provided socket '" + socket + "' is not of type SSLSocket"); 108 } 109 110 if (verificationSuccessful) { 111 // Verification successful, no need to delegate to base trust manager. 112 return; 113 } 114 115 if (base instanceof X509ExtendedTrustManager) { 116 ((X509ExtendedTrustManager) base).checkServerTrusted(chain, authType, socket); 117 } else { 118 base.checkServerTrusted(chain, authType); 119 } 120 } 121 122 @Override 123 public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { 124 if (base == null) { 125 LOGGER.warning("DaneExtendedTrustManager invalidly used for client certificate check and no fallback X509TrustManager specified"); 126 return; 127 } 128 129 LOGGER.info("DaneExtendedTrustManager invalidly used for client certificate check, forwarding request to fallback X509TrustManage"); 130 if (base instanceof X509ExtendedTrustManager) { 131 ((X509ExtendedTrustManager) base).checkClientTrusted(chain, authType, engine); 132 } else { 133 base.checkClientTrusted(chain, authType); 134 } 135 } 136 137 @Override 138 public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { 139 if (verifier.verifyCertificateChain(chain, engine.getPeerHost(), engine.getPeerPort())) { 140 // Verification successful, no need to delegate to base trust manager. 141 return; 142 } 143 144 if (base instanceof X509ExtendedTrustManager) { 145 ((X509ExtendedTrustManager) base).checkServerTrusted(chain, authType, engine); 146 } else { 147 base.checkServerTrusted(chain, authType); 148 } 149 } 150 151 @Override 152 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 153 if (base == null) { 154 LOGGER.warning("DaneExtendedTrustManager invalidly used for client certificate check and no fallback X509TrustManager specified"); 155 return; 156 } 157 158 LOGGER.info("DaneExtendedTrustManager invalidly used for client certificate check, forwarding request to fallback X509TrustManage"); 159 base.checkClientTrusted(chain, authType); 160 } 161 162 @Override 163 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 164 LOGGER.info("DaneExtendedTrustManager cannot be used without hostname information, forwarding request to fallback X509TrustManage"); 165 base.checkServerTrusted(chain, authType); 166 } 167 168 @Override 169 public X509Certificate[] getAcceptedIssuers() { 170 return base.getAcceptedIssuers(); 171 } 172}