Java HTTPS Server using Keytool - java

I'm using the following to initialize an HTTPS driven server for a secure website. The keystore command is as follows:
keytool -genkey -keyalg RSA -alias mykey -keystore keystore.jks -keypass password -storepass password -validity 365 -keysize 2048
After running the code I get a bad_certificate error message when I attempt to load my website and a yellow screen appears. What am I doing wrong?
String path = "C:\\Users\\Administrator\\Documents\\NetBeansProjects\\SSLTest5";
String file = path + "\\" + "keystore.jks";
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(file),"password".toCharArray());
// Create key manager
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, "password".toCharArray());
KeyManager[] km = keyManagerFactory.getKeyManagers();
// Create trust manager
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(keyStore);
TrustManager[] tm = trustManagerFactory.getTrustManagers();
// Initialize SSLContext
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(km, tm, null);
SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(443);
System.out.println("Waiting for client...");
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
HandleAccept(sslSocket);

Related

How to configure Two Way TLS Java App in a container?

I have two .cer files (one for client and other from server). I need to configure a docker container running a java spring boot app.
I'm a little confused with identity.jks, truststore.jks, client.cer and server.cer. In my POC (no docker) I generate all from scratch, by example:
Step 1) Generate public/private key for client
keytool -v -genkeypair -dname "CN=Willams,OU=Brasil,O=Dev,C=BR" -keystore ./identity.jks -storepass secret -keypass secret -keyalg RSA -keysize 2048 -alias client -validity 3650 -deststoretype pkcs12 -ext KeyUsage=digitalSignature,dataEncipherment,keyEncipherment,keyAgreement -ext ExtendedKeyUsage=serverAuth,clientAuth
Step 2) Create client certificate
keytool -v -exportcert -file ./client.cer -alias client -keystore ./identity.jks -storepass secret -rfc
Step 3) Include server certificate at truststore
keytool -v -importcert -file ./server.cer -alias server -keystore ./truststore.jks -storepass secret -noprompt
But how make the same thing, but using existing .cer (client and server) and a docker container?
My WebClient Code actual is:
#Value("${client.ssl.one-way-authentication-enabled:false}") boolean oneWayAuthenticationEnabled;
#Value("${client.ssl.two-way-authentication-enabled:false}") boolean twoWayAuthenticationEnabled;
#Value("${client.ssl.key-store:}") String keyStorePath;
#Value("${client.ssl.key-store-password:}") char[] keyStorePassword;
#Value("${client.ssl.trust-store:}") String trustStorePath;
#Value("${client.ssl.trust-store-password:}") char[] trustStorePassword;
#Bean
public WebClient webClientFe() throws SSLException {
HttpClient httpClient = HttpClient.create()
.secure(sslSpec -> sslSpec.sslContext(getTwoWaySslContext()));
return WebClient
.builder()
.uriBuilderFactory(getBaseFeUri())
.defaultHeader(HEADER_CACHE_CONTROL, HEADER_CACHE_CONTROL_VALUE)
.baseUrl(SERVER_URL)
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
private DefaultUriBuilderFactory getBaseFeUri() {
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(SERVER_URL);
factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);
return factory;
}
private SslContext getTwoWaySslContext() {
try(FileInputStream keyStoreFileInputStream = new FileInputStream(ResourceUtils.getFile(keyStorePath));
FileInputStream trustStoreFileInputStream = new FileInputStream(ResourceUtils.getFile(trustStorePath));
) {
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(keyStoreFileInputStream, keyStorePassword);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyStorePassword);
KeyStore trustStore = KeyStore.getInstance("jks");
trustStore.load(trustStoreFileInputStream, trustStorePassword);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
return SslContextBuilder.forClient()
.keyManager(keyManagerFactory)
.trustManager(trustManagerFactory)
.build();
} catch (Exception e) {
log.error("An error has occurred: ", e);
}
return null;
}

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();

PKIX path building failed: I unable to fixed it please provide us some solution

I have only .p12 file to call, its working fine when we are using by the postman, we want to call by java code, or springboot rest template
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream("/Users/sagir/Downloads/rest-api/src/main/resources/loudcloud-test.p12"),
"rudaN9YzjKwge5gu".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, "rudaN9YzjKwge5gu".toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance("PKCS12");
trustStore.load(
new FileInputStream(
"/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/security/cacerts"),
"changeit".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());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
URL url = new URL(null, "url",
new sun.net.www.protocol.https.Handler());
HttpURLConnection myURLConnection = (HttpURLConnection) url.openConnection();
You do not have a X.509 certifiate for import, you have a PKCS#12-keystore, so your command should look like:
keytool -importkeystore -v -srckeystore /home/mdsager/Downloads/spring-batch-demo/src/main/resources/loudcloud-test.p12 -srcstoretype PKCS12 -destkeystore /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts -deststoretype JCEKS

Android Two Way SSL Authentication With Volley

I am trying to make a two way SSL authentication to a server.
The server has SSL implemented to I need to make a HTTPS connection to the server. The server is with a third party vendor so i don't have server access. Although they have given me a server certificate test.crt.
Then I created my own self signed certificate by following the following commands.
generating keystore
keytool -genkey -alias myssl -keystore /home/user/mykey.keystore -validity 365
generating cer file
keytool -export -alias myssl -keystore /home/user/mykey.keystore -file /home/user/mykey.cer
import the cer file into the bks file
keytool -import -alias test_cer -file /home/user/mykey.cer -keystore /home/user/mykey.bks -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /home/user/bcprov-jdk15on-146.jar
Now I have 3 files : mykey.keystore, mykey.cer and mykey.bks.
So i gave the .cer file to the server vendors and they imported the certificate into their truststore.
Now, in my android application I try to connect to the server. I put the certificate from the server test.crt into the trust store and my mykey.cer into the key store and pass the trust manager and the key manager into the SSLContext.
Below is the relevant code.
allowTrustedSSL(this.activity);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(method,url,dataToSend, onResponseListener,onErrorListener);
/**
* Method implements self-signed certificates
* #param context
*/
public static void allowTrustedSSL(Context context){
/**
* We shall accept traffic with any host names
*/
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
Logger.d(TAG, "verify() called with: hostname = [" + hostname + "], session = [" + session + "]");
return true;
}
});
try{
//the NoSSLv3SocketFactory will disable the SSLv3
SSLSocketFactory noSSLv3Factory = new NoSSLv3SocketFactory(sslSocketFactoryGenerator(context));
HttpsURLConnection.setDefaultSSLSocketFactory(noSSLv3Factory);
} catch (Exception e) {
Logger.e(TAG, "allowTrustedSSL: "+e.getMessage());
e.printStackTrace();
}
}
public static SSLSocketFactory sslSocketFactoryGenerator(Context context) throws
UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException,
KeyStoreException, IOException, KeyManagementException {
//the test.crt file
TrustManagerFactory trustManagerFactory = getTrustManagerFactory(context.getResources().openRawResource(R.raw.test));
//the mykey.cer file
KeyManagerFactory keyManagerFactory = getKeyManagerFactory(context.getResources().openRawResource(R.raw.mykey),
MYKEY_PASS.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(),null);
return sslContext.getSocketFactory();
}
public static TrustManagerFactory getTrustManagerFactory(InputStream fileInput) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca;
try {
ca = cf.generateCertificate(fileInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
fileInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
return tmf;
}
public static KeyManagerFactory getKeyManagerFactory(InputStream fileInput,char[] password)
throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca;
try {
ca = cf.generateCertificate(fileInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
fileInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String keyManAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(keyManAlgorithm);
keyManagerFactory.init(keyStore, password);
return keyManagerFactory;
}
But when i start the connection to the server all I am getting is SSLException: Connection closed by peer. I have googled a lot for a proper documentation or example for implementing the two way ssl from android. And I have lost many precious days on figuring it out on myself.
Is my process of creating the certificates incorrect?

Reading Client Certificate in Servlet

I have a Client Server Communication scenario in JBOSS and browser as client(JAVA PROGRAM). Initially when the connection is made, Client sends its Certificate to Server. Server extracts the public key of client from certificate and thus communication will continue.
Now my question is
How to send certificate(.cer) from Client to Server?
How to receive the certificate and extract its public key in Server?
How to send certificate(.cer) from Client to Server?
Client certificate (.cer, .crt, .pem) and it's corresponding private key (.key) should be packaged into PKCS#12 (.p12, .pfx) or JKS (.jks) container first (keystore). You also should have server's CA certicate packaged as JKS (truststore).
Example using HttpClient 3.x:
HttpClient client = new HttpClient();
// truststore
KeyStore trustStore = KeyStore.getInstance("JKS", "SUN");
trustStore.load(TestSupertype.class.getResourceAsStream("/client-truststore.jks"), "amber%".toCharArray());
String alg = KeyManagerFactory.getDefaultAlgorithm();
TrustManagerFactory fac = TrustManagerFactory.getInstance(alg);
fac.init(trustStore);
// keystore
KeyStore keystore = KeyStore.getInstance("PKCS12", "SunJSSE");
keystore.load(X509Test.class.getResourceAsStream("/etomcat_client.p12"), "etomcat".toCharArray());
String keyAlg = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory keyFac = KeyManagerFactory.getInstance(keyAlg);
keyFac.init(keystore, "etomcat".toCharArray());
// context
SSLContext ctx = SSLContext.getInstance("TLS", "SunJSSE");
ctx.init(keyFac.getKeyManagers(), fac.getTrustManagers(), new SecureRandom());
SslContextedSecureProtocolSocketFactory secureProtocolSocketFactory = new SslContextedSecureProtocolSocketFactory(ctx);
Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) secureProtocolSocketFactory, 8443));
// test get
HttpMethod get = new GetMethod("https://127.0.0.1:8443/etomcat_x509");
client.executeMethod(get);
// get response body and do what you need with it
byte[] responseBody = get.getResponseBody();
You may find working example in this project see X509Test class.
With HttpClient 4.x configuration and syntax would be slightly different:
HttpClient httpclient = new DefaultHttpClient();
// truststore
KeyStore ts = KeyStore.getInstance("JKS", "SUN");
ts.load(PostService.class.getResourceAsStream("/truststore.jks"), "amber%".toCharArray());
// if you remove me, you've got 'javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated' on missing truststore
if(0 == ts.size()) throw new IOException("Error loading truststore");
// tmf
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
// keystore
KeyStore ks = KeyStore.getInstance("PKCS12", "SunJSSE");
ks.load(PostService.class.getResourceAsStream("/" + certName), certPwd.toCharArray());
// if you remove me, you've got 'javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated' on missing keystore
if(0 == ks.size()) throw new IOException("Error loading keystore");
// kmf
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, certPwd.toCharArray());
// SSL
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// socket
SSLSocketFactory socketFactory = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme sch = new Scheme("https", 8443, socketFactory);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
// request
HttpMethod get = new GetMethod("https://localhost:8443/foo");
client.executeMethod(get);
IOUtils.copy(get.getResponseBodyAsStream(), System.out);
How to receive the certificate and extract its public key in Server?
You server must be configurated to require X.509 client certificate authentication. Then during SSL handshake servlet container will recieve certificate, check it against trustore and provide it to application as a request attribute.
In usual case with single certificate you could use this method in servlet environment to extract certificate:
protected X509Certificate extractCertificate(HttpServletRequest req) {
X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
if (null != certs && certs.length > 0) {
return certs[0];
}
throw new RuntimeException("No X.509 client certificate found in request");
}

Categories