Java how to pass certyficate to OkHttpClient - java

i want to pass my certyficate to post request. I need to pass it becouse it wont work without this.
String pass = "password";
File file = new File("C:\\Users\\Test\\Desktop\\Program\\Certs\\TLS.p12");
InputStream stream = new FileInputStream(file);
KeyStore store = KeyStore.getInstance("PKCS12");
store.load(stream, pass.toCharArray());
PrivateKey key = (PrivateKey)store.getKey("TLS_CERT", pass.toCharArray());
System.out.println("Success");
SSLContext sslContext = SSLContext.getInstance("SSL");
TrustManagerFactory trustManagerFactory TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(store);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(store, "AGSZKeCnantL".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(),trustManagerFactory.getTrustManagers(), new SecureRandom());
OkHttpClient client = new OkHttpClient();
OkHttpClient.Builder builder = client.newBuilder();
builder.sslSocketFactory(sslContext.getSocketFactory()).build();
This is what i recive, i know i can disable TLS but server dont let me connect
Exception in thread "main" java.lang.UnsupportedOperationException: clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 9+
at okhttp3.internal.platform.Jdk9Platform.trustManager(Jdk9Platform.kt:61)
at okhttp3.OkHttpClient$Builder.sslSocketFactory(OkHttpClient.kt:751)
at Program.main(Program.java:71)
Can someone explain me how to fix this?

Related

How to send HTTPS request with Rest Assured using .crt certificate and public .key token

I need to send https request with REST assured having client .crt certificate and public key .key
How do I send request if my certificate and key in project like
"src/test/resources/certificate.crt"
"src/test/resources/key.key"
String clientCertificatePath = "certs/ClientCertificate.p12";
String trustStorePath = "C:/Program Files/Java/jre1.8.0_91/lib/security/cacerts";
String trustStorePassword = "changeit"; // default trust store password
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream(clientCertificatePath), clientPassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, clientPassword.toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream(trustStorePath), trustStorePassword.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] tms = tmf.getTrustManagers();
SSLContext sslContext = null;
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kms, tms, new SecureRandom());
SSLSocketFactory lSchemeSocketFactory=null;
lSchemeSocketFactory = new SSLSocketFactory(clientStore, clientPassword, trustStore);
// configure Rest Assured
RestAssured.config = RestAssured.config().sslConfig(sslConfig().with().sslSocketFactory(lSchemeSocketFactory).and().allowAllHostnames());
String response = RestAssured
.given()
.trustStore("src/test/resources/certificate.crt", "paasword")
.when()
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.header("Authorization", authHeader)
.baseUri("https://server.us.oracle.com:55898")
.queryParam("name", args)
.get("/validendpoint").prettyPrint();

Netty websocket client example with a given PKCS12

I have the client.p12 file and MyPassword, I am trying to establish the websocket connection using Netty code available over here. Currently I have the working example in OkHttpClient. But I am having a hard time to map that into netty.
My server gave me this domain to connect to "https://api.server.com"
In OkHttpClient the following code works
OkHttpClient client = getClient(info);
Request request = new Request.Builder().url("https://api.server.com" + "/messaging").build();
WebSocket webSocket = client.newWebSocket(request, listener);
Here the getClient code is following:
public static OkHttpClient getClient(ConnectionInfo info) {
KeyStore appKeyStore = KeyStore.getInstance("PKCS12");
appKeyStore.load(new FileInputStream("client.p12"), "MyPassword".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(appKeyStore, info.getPassword().toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException(
"Unexpected default trust managers:" + Arrays.toString(trustManagers));
}
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] {trustManager}, null);
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
OkHttpClient.Builder builder =
new OkHttpClient.Builder().sslSocketFactory(context.getSocketFactory(), trustManager);
builder.retryOnConnectionFailure(true);
return builder.build();
}
Now that code above works fine, I am trying to implement this in Netty. So looking at example code it only accepts the protocols ws and wss. While in the above example The HTTPS requests Upgraded to WebSocket using the appropriate headers. So my understanding is that If I provide the domain name as "wss:////api.server.com/messaging" Then it will first establish the https connection and then upgrade it to WebSocket.
Now I am not sure how to set the certificate and password.
// I have created a keyStore as following
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File("client.p12"));
try {
keyStore.load(instream, "MyPassword".toCharArray());
} finally {
instream.close();
}
final boolean ssl = "wss".equalsIgnoreCase(scheme);
final SslContext sslCtx;
if (ssl) {
// How to specify the above keystore with this client?
sslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
} else {
sslCtx = null;
}
SSlContextBuilder has a method that takes a KeyManagerFactory:
SslContextBuilder.forClient()
.keyManager(keyManagerFactory)
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();

Using .p12 file to execute request to rest server

I'm trying to execute requests to a server which provided me with a .p12 file in order to make secure connection with rest services, I'm doing the following in order to set the HttpClient with the key:
SSLContext sslContext =SSLContextBuilder
.create().loadKeyMaterial(ResourceUtils.getFile("classpath:keystore/file.p12"), "secret".toCharArray(), "secret".toCharArray())
.build();
return HttpClientBuilder
.create()
.setConnectionManager(connManager())
.setSSLContext(sslContext)
.setDefaultRequestConfig(requestConfig())
.build();
When I execute the request with OAuth2RestOperations I got:
401 , Non existing certificate or invalid
I recently had a similar requirement. Here is the code I used:
KeyStore clientStore = KeyStore.getInstance("PKCS12");
try {
clientStore.load(ResourceUtils.getFile("classpath:keystore/file.p12"), "secret".toCharArray());
} catch (IOException e) {
//handle exception
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, "secret".toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kms, null, new SecureRandom());
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClientBuilder builder = HttpClientBuilder.create();
return builder.setSSLSocketFactory(socketFactory).build();
I think this is actually a duplicate question.
Please see this answer for this question Java HTTPS client certificate authentication.
In all examples you need to call loadKeyMaterial method with KeyStore
public SSLContextBuilder loadKeyMaterial(KeyStore keystore,
Load the keyStore using file path, for example:
keyStore = KeyStore.getInstance("PKCS12");
FileInputStream inputStream = new FileInputStream(new File(certPath));
keyStore.load(inputStream, certPassword.toCharArray());

Trying to pass along x509 client certificate to second server

I'm trying to give server "A" the ability to connect to server "B" using the same X509 client certificate it received from the user. Here are the basics of where I am so far:
public int makeRemoteCall() {
URL url = new URL("https://host.com/service/request");
HttpsURLConnection conn = url.openConnection();
SSLSocketFactory factory = getFactoryFromSessionCert();
conn.setSSLSocketFactory(factory);
int responseCode = conn.getResponseCode();
return responseCode;
}
public static SSLSocketFactory getFactoryFromSessionCert() throws Exception {
HttpServletRequest request = getRequest();
X509Certificate[] certs = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setCertificateEntry("client_cert", certs[0]);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, null);
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, null);
return context.getSocketFactory();
}
I am able to retrieve the client's certificate without trouble, and can verify that it does indeed end up in keyStore. But the certificate doesn't seem to make it into keyManagerFactory.
I thought the issue was that I'm not providing a password in keyManagerFactory.init(keyStore, null), so I tried providing it but without success. And should I even have to? I understand that I would need a password if I were loading certificates and keys from a protected file, but here I'm just trying to pass along an already exposed public certificate.
As further background, this basic scheme works if I replace getFactoryFromSessionCert() with this:
public static SSLSocketFactory getFactory(File pKeyFile, String pKeyPassword) throws Exception {
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyInput = new FileInputStream(pKeyFile);
keyStore.load(keyInput, pKeyPassword.toCharArray());
keyInput.close();
keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
return context.getSocketFactory();
}
So, what am I not understanding? And how should I pass along a client certificate?

Java app to use two separate truststores

From a java app, I would like to use two truststores, one to connect to a jms broker, and another to connect to a web service. I know I can import the certs into one truststore, and that works. However, I was wandering whether I can pass a list of different truststores using system property javax.net.ssl.trustStore ?
No, you can't. To use different truststores you should set one of them or both programmatically.
See example below from this post :
SSLContext ssl = SSLContext.getInstance("SSLv3");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
String password = Configuration.getConfig("keyStorePassword");
store.load(new FileInputStream(new File(Configuration.getConfig("keyStore"))), password.toCharArray());
kmf.init(store, password.toCharArray());
KeyManager[] keyManagers = new KeyManager[1];
keyManagers = kmf.getKeyManagers();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(store);
TrustManager[] trustManagers = tmf.getTrustManagers();
ssl.init(keyManagers, trustManagers, new SecureRandom());
HttpsConfigurator configurator = new HttpsConfigurator(ssl);
Integer port = Integer.parseInt(Configuration.getConfig("port"));
HttpsServer httpsServer = HttpsServer.create(new InetSocketAddress(Configuration.getConfig("host"), port), 0);
httpsServer.setHttpsConfigurator(configurator);
Implementor implementor = new Implementor(); // class with #WebService etc.
HttpContext context = (HttpContext) httpsServer.createContext("/EventWebService");
Endpoint endpoint = Endpoint.create( implementor );
endpoint.publish(context);

Categories