A helper class to validate the usage of TLSA records.
| 44 | * A helper class to validate the usage of TLSA records. |
| 45 | */ |
| 46 | public class DaneVerifier { |
| 47 | private static final Logger LOGGER = Logger.getLogger(DaneVerifier.class.getName()); |
| 48 | |
| 49 | private final DnssecClient client; |
| 50 | |
| 51 | public DaneVerifier() { |
| 52 | this(new DnssecClient()); |
| 53 | } |
| 54 | |
| 55 | public DaneVerifier(DnssecClient client) { |
| 56 | this.client = client; |
| 57 | } |
| 58 | |
| 59 | /** |
| 60 | * Verifies the certificate chain in an active {@link SSLSocket}. The socket must be connected. |
| 61 | * |
| 62 | * @param socket A connected {@link SSLSocket} whose certificate chain shall be verified using DANE. |
| 63 | * @return Whether the DANE verification is the only requirement according to the TLSA record. |
| 64 | * If this method returns {@code false}, additional PKIX validation is required. |
| 65 | * @throws CertificateException if the certificate chain provided differs from the one enforced using DANE. |
| 66 | */ |
| 67 | public boolean verify(SSLSocket socket) throws CertificateException { |
| 68 | if (!socket.isConnected()) { |
| 69 | throw new IllegalStateException("Socket not yet connected."); |
| 70 | } |
| 71 | return verify(socket.getSession()); |
| 72 | } |
| 73 | |
| 74 | /** |
| 75 | * Verifies the certificate chain in an active {@link SSLSession}. |
| 76 | * |
| 77 | * @param session An active {@link SSLSession} whose certificate chain shall be verified using DANE. |
| 78 | * @return Whether the DANE verification is the only requirement according to the TLSA record. |
| 79 | * If this method returns {@code false}, additional PKIX validation is required. |
| 80 | * @throws CertificateException if the certificate chain provided differs from the one enforced using DANE. |
| 81 | */ |
| 82 | public boolean verify(SSLSession session) throws CertificateException { |
| 83 | try { |
| 84 | return verifyCertificateChain(convert(session.getPeerCertificates()), session.getPeerHost(), session.getPeerPort()); |
| 85 | } catch (SSLPeerUnverifiedException e) { |
| 86 | throw new CertificateException("Peer not verified", e); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | /** |
| 91 | * Verifies a certificate chain to be valid when used with the given connection details using DANE. |
| 92 | * |
| 93 | * @param chain A certificate chain that should be verified using DANE. |
| 94 | * @param hostName The DNS name of the host this certificate chain belongs to. |
| 95 | * @param port The port number that was used to reach the server providing the certificate chain in question. |
| 96 | * @return Whether the DANE verification is the only requirement according to the TLSA record. |
| 97 | * If this method returns {@code false}, additional PKIX validation is required. |
| 98 | * @throws CertificateException if the certificate chain provided differs from the one enforced using DANE. |
| 99 | */ |
| 100 | public boolean verifyCertificateChain(X509Certificate[] chain, String hostName, int port) throws CertificateException { |
| 101 | DnsName req = DnsName.from("_" + port + "._tcp." + hostName); |
| 102 | DnssecQueryResult result; |
| 103 | try { |