Skip to content

Commit

Permalink
Refactored SocketConnector to throw HostnameUnverifiedException
Browse files Browse the repository at this point in the history
instead of SSLPeerUnverifiedException when the certificate of
the peer does not match the expected hostname.

This change is related to the pull request #107 (Verify that
certificate is valid for server hostname).
  • Loading branch information
TakahikoKawasaki committed Apr 23, 2017
1 parent f553a1a commit a158795
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ private void skipHeaders(InputStream input) throws IOException
* To be able to verify the hostname of the certificate received
* if a connection is made to an https/wss endpoint, access to this
* hostname is required.
*
*
* @return the hostname of the server the proxy is asked to connect to.
*/
String getProxiedHostname()
Expand Down
48 changes: 25 additions & 23 deletions src/main/java/com/neovisionaries/ws/client/SocketConnector.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Neo Visionaries Inc.
* Copyright (C) 2016-2017 Neo Visionaries Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,8 +18,6 @@

import java.io.IOException;
import java.net.Socket;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
Expand Down Expand Up @@ -111,20 +109,12 @@ private void doConnect() throws WebSocketException
{
// Connect to the server (either a proxy or a WebSocket endpoint).
mSocket.connect(mAddress.toInetSocketAddress(), mConnectionTimeout);

if (mSocket instanceof SSLSocket)
{
// Verify that the hostname matches the certificate here since
// this is not automatically done by the SSLSocket.
OkHostnameVerifier hostnameVerifier = OkHostnameVerifier.INSTANCE;

SSLSession sslSession = ((SSLSocket) mSocket).getSession();

if (!hostnameVerifier.verify(mAddress.getHostname(), sslSession))
{
throw new SSLPeerUnverifiedException("Hostname does not match certificate ("
+ sslSession.getPeerPrincipal() + ")");
}
verifyHostname((SSLSocket)mSocket, mAddress.getHostname());
}
}
catch (IOException e)
Expand All @@ -147,6 +137,26 @@ private void doConnect() throws WebSocketException
}


private void verifyHostname(SSLSocket socket, String hostname) throws HostnameUnverifiedException
{
// Hostname verifier.
OkHostnameVerifier verifier = OkHostnameVerifier.INSTANCE;

// The SSL session.
SSLSession session = socket.getSession();

// Verify the hostname.
if (verifier.verify(hostname, session))
{
// Verified. No problem.
return;
}

// The certificate of the peer does not match the expected hostname.
throw new HostnameUnverifiedException(socket, hostname);
}


/**
* Perform proxy handshake and optionally SSL handshake.
*/
Expand Down Expand Up @@ -192,20 +202,12 @@ private void handshake() throws WebSocketException
// Start the SSL handshake manually. As for the reason, see
// http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/samples/sockets/client/SSLSocketClient.java
((SSLSocket)mSocket).startHandshake();

if (mSocket instanceof SSLSocket)
{
// Verify that the proxied hostname matches the certificate here since
// this is not automatically done by the SSLSocket.
OkHostnameVerifier hostnameVerifier = OkHostnameVerifier.INSTANCE;

SSLSession sslSession = ((SSLSocket) mSocket).getSession();

if (!hostnameVerifier.verify(mProxyHandshaker.getProxiedHostname(), sslSession))
{
throw new SSLPeerUnverifiedException("Proxied hostname " + mProxyHandshaker.getProxiedHostname()
+ " does not match certificate (" + sslSession.getPeerPrincipal() + ")");
}
verifyHostname((SSLSocket)mSocket, mProxyHandshaker.getProxiedHostname());
}
}
catch (IOException e)
Expand Down

0 comments on commit a158795

Please sign in to comment.