I'd like to know how I can implement a server socket to let it able to identify and use
correct certificate according with the certificate being used by client to proceed
handshake communication with the server.
Explaining better, in the server side is:
AppServerSideSocket.jar
private keystore: privateKeyApp (type JKS, generated with keytool)
public keystore : publicKeyApp (type JKS, shared with all clients)
And in the client side ...
AppClientSideSocket.jar
- public keystore : publicKeyApp
The AppServerSideSocket.jar listening clients requests and once received proocess
information sent by clients
The AppClientSideSocket.jar connect with the server using SSL using publicKeyApp without
verify server hostname and after handshake send information for the AppServerSideSocket application.
Now I've another client application, AppClientSideSocketNEW.jar, and this verify server hostname to make
communication with the server. In this case, the CN used in the public certificate on the client side
must be match with the hostname where AppServerSideSocket.jar are.
Originaly the connection was configured in this way on the server side:
if (usingSSLConn) {
System.setProperty("javax.net.ssl.keyStore", "privateKeyApp");
System.setProperty("javax.net.ssl.keyStorePassword", "privateKeyAppPassword");
SSLServerSocketFactory sslServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket serverSocketApp = sslServerSocketFactory.createServerSocket(Port);
} else
serverSocketApp = new ServerSocket(Port);
}
All the clients received the same publicKeyApp and connect with the server without verify hostname, so doesn't matter
if the server where server socket application (AppServerSideSocket.jar) is installed in the server with hostname is
badServer1.com and the CN of key in privateKeyApp and publicKeyApp is setted with goodServer1.com, because all the clients don't verify hostname or the CN attribute of the key.
Bellow is showed a piece of this kind of connection:
private static final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
System.setProperty("javax.net.ssl.trustStore", publicKey1);
System.getProperties().setProperty("java.protocol.handler.pkgs",
"javax.net.ssl.internal.www.protocol");
HttpsURLConnection.setDefaultHostnameVerifier(DO_NOT_VERIFY);
...
SOAPConnectionFactory soapConn = SOAPConnectionFactory.newInstance();
SOAPConnection connection = soapConn.createConnection();
...
URL endpoint = new URL(hostname + ":" + port);
But the new client (AppClientSideSocketNEW.jar) do this verification obrigatorily, now is necessary provide a new certificate
for this client with new value for CN attribute reflecting the correct hostname CN where the server socket is.
I don't have access to second client and I'm sure that it do hostname verification.
So I created two new key-pair ceritificates (privateKeyAppNew and publicKeyAppNew) and aparently the communications happened
with success between the server using this new key-pair and new client using this new public publicKeyAppNew key.
But I need continue to use the old key-pair for old clients. I'd like to know how can I deal with this.
Using a keymanager let me able to verify the client certificate on the server app when client try to connect and
choose the apropriate and do the handshake using the correct certificate?
Or I need disctinct ssl socket connection in different ports for which kind of clients?
You need to set a Hostname Verifier in the connection you want to verify the CN of the server certificate.
Plenty of examples if you google e.g.
Hostname verifier 1 this creates a trust all names but you can modify it as you need
HttpClient and SSL same in the answer her
Related
To be able to support a client cert, I extended
ProxyHttpConnectionManager extends DefaultApacheHttpClientConnectionManagerFactory and have overridden newConnectionManager
if (disableSslValidation) {
try {
final SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial((new File(keystore)), keyStorePass.toCharArray(), keyStorePass.toCharArray())
.loadTrustMaterial(new File(trustStore)).build();
registryBuilder.register(HTTPS_SCHEME, new SSLConnectionSocketFactory(
sslContext, NoopHostnameVerifier.INSTANCE));
}
catch (Exception e) {
LOG.warn("Error creating SSLContext", e);
}
Thats the only customization I have done. Zuul does not keep the HttpConnections alive for servers that need a client cert. For all other servers on Https, previous connections are reused.
Summary for SSL Logs and TCP Dumps
No Client Cert requried
SYN , Client Hello
Server Hello
Data Exchange
Request 2- Data Exchange
Close after timeout
Servers with Client Cert Required
SYN CLient Hello
Server Hello
Data Exchange
FIN
Request 2 - SYN
Hello's again
Data Exchange
Fin
I'm attempting to implement a WebSocket Client in an application that supports secure transmissions through SSL. The application already supports standard SSL connections over HTTP, by implementing custom Key and Trust managers (these custom implementations are in place to prompt the user for a certificate when needed).
I'm having trouble getting a secure connection to our remote WebSocket endpoint. The failure is occurring during the handshake. I've tried two different implementations of the WebSocket API (both Tyrus and Jetty), and both fail in the same way, which, of course, leads me to point to our SSL implementation.
As I mentioned, the failure is occurring during the handshake. It seems that the connection cannot figure out that there are client certificates that are signed by the supported authorities returned from the server. I'm stumped to figure out if I haven't supplied the client certificates to the WebSocket API correctly, or if our custom Key/Trust managers are even getting used.
Here's a dump of the SSL Debug logs:
*** CertificateRequest
Cert Types: RSA, DSS
Cert Authorities:
(list of about 15 cert authorities supported by the server)
*** ServerHelloDone
Warning: no suitable certificate found - continuing without client authentication
*** CertificateChain
<empty>
***
I've set breakpoints in our TrustManager implementation, to determine if they are ever getting called, and it seems that they are not being called at this point.
I've been attempting to debug this for a few days now, and am running out of things to try.
Any suggestions would be greatly appreciated!
Here's a snippet of the Jetty Code:
SSLContext context = SSLContext.getInstance("TLS");
// getKeyManagers / getTrustManagers retrieves an
// array containing the custom key and trust manager
// instances:
KeyManager[] km = getKeyManagers();
TrustManager[] tm = getTrustManagers();
context.init(km, tm, null);
SslContextFactory contextFactory = new SslContextFactory();
contextFactory.setContext(context);
WebSocketClient client = new WebSocketClient(contextFactory);
SimpleEchoClient echoClient = new SimpleEchoClient();
try {
client.start();
ClientUpgradeRequest request = new ClientUpgradeRequest();
Future<Session> connection = client.connect(echoClient, uri, request);
Session session = connection.get();
// if everything works, do stuff here
session.close();
client.destroy();
} catch (Exception e) {
LOG.error(e);
}
can you try with rejectUnAuthorized:false so that your certificates for which your browser is unable to authorize will skip the authorization.
var ws = new WebSocket('wss://localhost:xxxx', {
protocolVersion: 8,
origin: 'https://localhost:xxxx',
rejectUnauthorized: false
});
I know the reason why browsers and java7 are not affected is because they send Server Name Indication-SNI as part of the SSL information. So, apache knows what virtual host to use before starting SSL handshake and returns the proper certificate. Java 6 doesn't support SNI. So My question is, how do I verify and allow certificate to be accepted in java 6.
I made a spring client to consume webservice, Here is my code
public class classname1 {
static {
System.setProperty("javax.net.ssl.trustStore", "E://Workspace//keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
System.setProperty("https.protocols", "SSLv3");
System.setProperty("https.protocols", "TLSv1");
}
static {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
{
public boolean verify(String hostname, SSLSession session)
{
if (hostname.equals("192.168.10.22"))
return true;
return false;
}
});
}
private static void main(String[] args) {
try {
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection soapConnection = soapConnectionFactory.createConnection();
String url = "https://192.168.10.22/getInformationSearch.asmx?wsdl";
SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), url);
printSOAPResponse(soapResponse);
soapConnection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static SOAPMessage createSOAPRequest() throws Exception {
// ... Code for request, which will be hitted to url
}
private static void printSOAPResponse(SOAPMessage soapResponse) throws Exception {
// ... Code for response, which will fetch information from webservice
// URL
}
}
As you can see code, I made two methods, 1. for Request createSOAPRequest() 2. for Response printSOAPResponse(). (Url name is changed in above snippet)
In main() method, below line will generate request and send that request to given url SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), url); after that it goes to static block as shown above HttpsURLConnection.setDefaultHostnameVerifier() method.
At that time,debugger says: ssl handshake failed and SSL peer shut down incorrectly. It happens only in JAVA 6 but these code working proper with java 7/8.
Instead of that static block, I have tried below code in java 6
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName,
SSLSession session) {
return true;
}
};
But it won't work anyhow!!!
I am using following jars xercesImpl.jar,saaj-api.jar,saaj-impl.jar,spring-ws-core-1.5.6.jar,spring-ws-security-1.5.6.jar and Certificate for this SSL domain has been imported into keystore and It works in java7/8, So there is no issue in truststore right? (I made 2 certificate using keytool of java 6 and 7 as well, both works fine in java7/8 but not in 6)
I followed this thread but it wont work. So is there any alternative way to verify certificate and get response in java 6 environment, or should I change any JAR ?
You can't if the server isn't configured to allow you to connect without SNI.
Without SNI, the server cannot tell which virtual host you want until after the SSL connection has been established.
To see the difference, if you have OpenSSL, you can use the s_client option to extract the different certificates presented, or perhaps note a failure to connect when you don't use SNI:
SNI:
echo | openssl s_client -servername www.virtualhost.com -connect 192.168.1.55:443 | openssl x509 -text
Replace 192.168.1.55 with the actual IP address of the server, and www.virtualhost.com with the host name of the virtual host you want to connect to. The echo command prepended to the pipeline prevents openssl from hanging in a wait for input.
Without SNI:
echo | openssl s_client -connect 192.168.1.55:443 | openssl x509 -text
Without SNI, you may see a completely different certificate, or you may get a connection error.
As you already mentioned Java 6 does not support SNI. But, the problem of missing SNI is not only with verifying the certificate (because the server sends the wrong certificate) but also that depending on the servers configuration the server will cause a handshake error if the SNI extension is not present and does not point to a hostname available at the server. And this is obviously the case here:
... ssl handshake failed and SSL peer shut down incorrectly. It happens only in JAVA 6 but these code working proper with java 7/8.
Trying to change the validation of the certificate as you've tried will not help at all in this case because the error occurs before the client even has a certificate to verify. This means that there is no way around it: you need to support SNI in your client if you want to communicate with this specific server.
I am using jolokia client to connect to my fuse server, which is using https for web. I am getting the below exception.
org.jolokia.client.exception.J4pException: IO-Error while contacting the server: javax.net.ssl.SSLException: hostname in certificate didn't match: <10.16.205.20> !=
at org.jolokia.client.J4pClient.mapException(J4pClient.java:333)
at org.jolokia.client.J4pClient.execute(J4pClient.java:198)
at org.jolokia.client.J4pClient.execute(J4pClient.java:168)
at org.jolokia.client.J4pClient.execute(J4pClient.java:117)
I have already imported the certificate of 10.16.205.20 to my local truststrore (cacerts) from where my client application is running jolokia client. I have also verified the hosts file have entry for the domain that is being used in the certificate on 10.16.205.20 server. I am using the below code to connect.
J4pClient client = J4pClient.url(baseUrl).user(user.getName()).password(user.getPassword()).authenticator(new BasicAuthenticator().preemptive()).build();
J4pExecRequest request = new J4pExecRequest("org.apache.karaf:type=bundles,name=root","list");
J4pExecResponse response = client.execute(request);
JSONObject obj = response.asJSONObject();
((CloseableHttpClient)client.getHttpClient()).close();
This code is running fine with the server deployed with http. Please let me know, if I am missing something.
You need to let your client use a ConnectionSocketFactory that bypasses this check.
For instance take a look at the following code (Code is Kotlin but you can easily translate it to java, I guess)
val sslCtx: SSLContext = SSLContexts
.custom()
.loadTrustMaterial(null, TrustSelfSignedStrategy())
.build()
val cf: ConnectionSocketFactory = SSLConnectionSocketFactory(sslCtx, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
J4pClient.url(s.jolokiaUrl)
.sslConnectionSocketFactory(cf)
.connectionTimeout(timeout.toMillis().toInt())
.build()
Can somebody tell me how can i ignore the ssl certificate during web service call.
I am calling https weburl to get api response but getting peer not authenticated error.
Old examples are not working as some of methods are deprecated so can somebody tell me/ provide some sample code so that i will not get this error.
I just came to know that the problem is coming due to Certificate.
I am using 3rd party API for db calls & they have ssl certificate for their domain
i.e. www.dbprovider.com (SSL certificate is *.dbprovider.com)
& they created subdomain for us which look like myapp.dbprovider.com
So now the problem is no peer certificate is available when i try to hit through command
openssl s_client -ssl3 -showcerts -connect myapp.dbprovider.com:443
openssl s_client -tls1 -showcerts -connect myapp.dbprovider.com:443
Can somebody tell me what i should now do with it. Is there any control on dbprovider site so that they can provide me some configuration or i have to write code to ignore their certificate (but for ignoring certificate we are not getting their peer certificate)
Use a custom SSLSocketFactory as described here: http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e512. One such factory that ignores self-signed certs is EasySSLProtocolSocketFactory.
ProtocolSocketFactory factory = new EasySSLProtocolSocketFactory();
try {
URI uri = new URI(config.getBaseUrl());
int port = uri.getPort();
if (port == -1) {
port = 443;
}
Protocol easyHttps = new Protocol(uri.getScheme(), factory, port);
hostConfiguration.setHost(uri.getHost(), port, easyHttps);
} catch (URISyntaxException e) {
throw new IOException("could not parse URI " + config.getBaseUrl(), e);
}
Source: http://frightanic.com/software-development/self-signed-certificates-in-apache-httpclient/