[jbosstools-issues] [JBoss JIRA] (JBIDE-19594) SSL callback: provide meaningful hostname verifier, drop always accepting hostnames
Andre Dietisheim (JIRA)
issues at jboss.org
Wed Apr 15 05:17:19 EDT 2015
[ https://issues.jboss.org/browse/JBIDE-19594?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13059162#comment-13059162 ]
Andre Dietisheim edited comment on JBIDE-19594 at 4/15/15 5:17 AM:
-------------------------------------------------------------------
An example of such a hostname verifier can be found in android land:
http://developer.android.com/reference/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.html
Another one can be found here: https://tersesystems.com/2014/03/23/fixing-hostname-verification/
{code}
class DefaultHostnameVerifier extends HostnameVerifier {
private val logger = LoggerFactory.getLogger(getClass)
def hostnameChecker: HostnameChecker = HostnameChecker.getInstance(HostnameChecker.TYPE_TLS)
def matchKerberos(hostname: String, principal: Principal) = HostnameChecker.`match`(hostname, principal.asInstanceOf[KerberosPrincipal])
def isKerberos(principal: Principal): Boolean = principal != null && principal.isInstanceOf[KerberosPrincipal]
def verify(hostname: String, session: SSLSession): Boolean = {
logger.debug(s"verify: hostname = $hostname")
val checker = hostnameChecker
val result = try {
session.getPeerCertificates match {
case Array(cert: X509Certificate, _*) =>
try {
checker.`match`(hostname, cert)
// Certificate matches hostname
true
} catch {
case e: CertificateException =>
// Certificate does not match hostname
logger.debug("verify: Certificate does not match hostname", e)
false
}
case notMatch =>
// Peer does not have any certificates or they aren't X.509
logger.debug(s"verify: Peer does not have any certificates: $notMatch")
false
}
} catch {
case _: SSLPeerUnverifiedException =>
// Not using certificates for verification, try verifying the principal
try {
val principal = session.getPeerPrincipal
if (isKerberos(principal)) {
matchKerberos(hostname, principal)
} else {
// Can't verify principal, not Kerberos
logger.debug(s"verify: Can't verify principal, not Kerberos")
false
}
} catch {
case e: SSLPeerUnverifiedException =>
// Can't verify principal, no principal
logger.debug("Can't verify principal, no principal", e)
false
}
}
logger.debug("verify: returning {}", result)
result
}
}
{code}
and here: http://kevinlocke.name/bits/2012/10/03/ssl-certificate-verification-in-dispatch-and-asynchttpclient/
{code}
/* An example program using AsyncHttpClient with SSL certificate verification
*
* To the extent possible under law, Kevin Locke has waived all copyright and
* related or neighboring rights to this work.
* A legal description of this waiver is available in LICENSE.txt.
*/
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.Response;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.ExecutionException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.security.auth.kerberos.KerberosPrincipal;
import sun.security.util.HostnameChecker;
/** Implements the "MyDownloader" application */
public class MyDownloader {
/** HostnameVerifier implementation which implements the same policy as the
* Java built-in pre-HostnameVerifier policy.
*/
private static class MyHostnameVerifier implements HostnameVerifier {
/** Checks if a given hostname matches the certificate or principal of
* a given session.
*/
private boolean hostnameMatches(String hostname, SSLSession session) {
HostnameChecker checker =
HostnameChecker.getInstance(HostnameChecker.TYPE_TLS);
boolean validCertificate = false, validPrincipal = false;
try {
Certificate[] peerCertificates = session.getPeerCertificates();
if (peerCertificates.length > 0 &&
peerCertificates[0] instanceof X509Certificate) {
X509Certificate peerCertificate =
(X509Certificate)peerCertificates[0];
try {
checker.match(hostname, peerCertificate);
// Certificate matches hostname
validCertificate = true;
} catch (CertificateException ex) {
// Certificate does not match hostname
}
} else {
// Peer does not have any certificates or they aren't X.509
}
} catch (SSLPeerUnverifiedException ex) {
// Not using certificates for peers, try verifying the principal
try {
Principal peerPrincipal = session.getPeerPrincipal();
if (peerPrincipal instanceof KerberosPrincipal) {
validPrincipal = HostnameChecker.match(hostname,
(KerberosPrincipal)peerPrincipal);
} else {
// Can't verify principal, not Kerberos
}
} catch (SSLPeerUnverifiedException ex2) {
// Can't verify principal, no principal
}
}
return validCertificate || validPrincipal;
}
public boolean verify(String hostname, SSLSession session) {
if (hostnameMatches(hostname, session)) {
return true;
} else {
// TODO: Add application-specific checks for
// hostname/certificate match
return false;
}
}
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("Usage: myhttp <URL>");
} else {
String url = args[0];
SSLContext context = null;
try {
context = SSLContext.getInstance("TLS");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return;
}
try {
context.init(null, null, null);
} catch (KeyManagementException e) {
e.printStackTrace();
return;
}
AsyncHttpClient client = new AsyncHttpClient(
new AsyncHttpClientConfig.Builder()
.setSSLContext(context)
.setHostnameVerifier(new MyHostnameVerifier())
.build()
);
Response response = null;
try {
response = client.prepareGet(url).execute().get();
} catch (InterruptedException e) {
e.printStackTrace();
return;
} catch (ExecutionException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
if (response.getStatusCode() / 100 == 2) {
try {
String responseBody = response.getResponseBody();
System.err.println("Successfully downloaded " + url);
System.out.println(responseBody);
} catch (IOException e) {
e.printStackTrace();
return;
}
} else {
System.err.println("Failure downloading " + url +
": HTTP Status " + response.getStatusCode());
}
}
}
}
{code}
was (Author: adietish):
An example of such a hostname verifier can be found in android land:
http://developer.android.com/reference/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.html
Another one can be found here: https://tersesystems.com/2014/03/23/fixing-hostname-verification/
{code}
class DefaultHostnameVerifier extends HostnameVerifier {
private val logger = LoggerFactory.getLogger(getClass)
def hostnameChecker: HostnameChecker = HostnameChecker.getInstance(HostnameChecker.TYPE_TLS)
def matchKerberos(hostname: String, principal: Principal) = HostnameChecker.`match`(hostname, principal.asInstanceOf[KerberosPrincipal])
def isKerberos(principal: Principal): Boolean = principal != null && principal.isInstanceOf[KerberosPrincipal]
def verify(hostname: String, session: SSLSession): Boolean = {
logger.debug(s"verify: hostname = $hostname")
val checker = hostnameChecker
val result = try {
session.getPeerCertificates match {
case Array(cert: X509Certificate, _*) =>
try {
checker.`match`(hostname, cert)
// Certificate matches hostname
true
} catch {
case e: CertificateException =>
// Certificate does not match hostname
logger.debug("verify: Certificate does not match hostname", e)
false
}
case notMatch =>
// Peer does not have any certificates or they aren't X.509
logger.debug(s"verify: Peer does not have any certificates: $notMatch")
false
}
} catch {
case _: SSLPeerUnverifiedException =>
// Not using certificates for verification, try verifying the principal
try {
val principal = session.getPeerPrincipal
if (isKerberos(principal)) {
matchKerberos(hostname, principal)
} else {
// Can't verify principal, not Kerberos
logger.debug(s"verify: Can't verify principal, not Kerberos")
false
}
} catch {
case e: SSLPeerUnverifiedException =>
// Can't verify principal, no principal
logger.debug("Can't verify principal, no principal", e)
false
}
}
logger.debug("verify: returning {}", result)
result
}
}
{code}
> SSL callback: provide meaningful hostname verifier, drop always accepting hostnames
> -----------------------------------------------------------------------------------
>
> Key: JBIDE-19594
> URL: https://issues.jboss.org/browse/JBIDE-19594
> Project: Tools (JBoss Tools)
> Issue Type: Enhancement
> Components: openshift
> Affects Versions: 4.3.0.Alpha2
> Reporter: Andre Dietisheim
> Fix For: 4.3.0.Beta1
>
>
> We're currently using an SSL callback that will allow users to get informed and act upon "faulty" certificates (ex. self-signed ones) and mismatches btw. the host we're talking to and the one that is referenced in the ssl certificate:
> {code:title=com.openshift.client.IHttpClient.ISSLCertificateCallback}
> public interface ISSLCertificateCallback {
> public boolean allowCertificate(X509Certificate[] chain);
> public boolean allowHostname(String hostname, SSLSession session);
> }
> {code}
> The callback that we are using in JBT is presenting a dialog in case the jdk cannot verify the certificate (ex. self signed certificates) and allows the user to accept/deny it.
> In case the jdk cannot verify the hostname (the host we're talking to is not matching the host that's referenced in the certificate) we're currently always accepting the hostname:
> {code:title=org.jboss.tools.openshift.express.internal.ui.wizard.connection.SSLCertificateCallback}
> @Override
> public boolean allowHostname(String hostname, SSLSession sslSession) {
> return true;
> }
> {code}
> We should find a meaningfull implementation of such a verification that does not simply always accept it. A first idea would be to present the mismatch to the user and allow it to accept/refute it.
> This issue came up JBIDE-19581 when there was no callback installed which made the hostname verification failed as in jdk. The ssl certificate used by
--
This message was sent by Atlassian JIRA
(v6.3.11#6341)
More information about the jbosstools-issues
mailing list