Can Java connect to wildcard ssl - java

We wish to buy a wild-card SSL certificate as we have a lot of sub-domains. However I don't know if Java trusts wild-card certificates. As people connect into our API via SSL it will not be sufficient for us to force all third parties we communicate with to add our SSL certificate into their local truststore.
At the moment I'm facing a dilemma to buy a wildcard certificate from a java trusted issuer or buy multiple certs one per sub-domain.
Do other languages also have a truststore? If so does anyone know if wildcard certificates work with them also.

The default implementation in Sun's JSSE doesn't support wildcard. You need to write your own X509TrustManager to handle wildcard.
However, Java supports SAN (Subject Alternative Names) since Java 5. If you have less than 20 names, you can get one certificate for all of them. It may be cheaper than a wildcard cert.

I've attempted this with java 6.
It appears to work correctly. I've succesfully read headers and body content from a file that had a wildcard SSL certificate.
package com.example.test;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class SSLTEST {
public static void main(String[] args) {
try {
URL url = new URL("https://test.example.com/robots.txt");
URLConnection connection = null;
try {
connection = url.openConnection();
} catch (IOException e) {
e.printStackTrace();
}
Map<String, List<String>> fields = connection.getHeaderFields();
Iterator<Entry<String, List<String>>> headerIterator = fields.entrySet().iterator();
System.out.println("HEADERS");
System.out.println("-------------------------------");
while (headerIterator.hasNext()){
Entry<String, List<String>> header = headerIterator.next();
System.out.println(header.getKey()+" :");
Iterator<String> valueIterator = header.getValue().iterator();
while (valueIterator.hasNext()){
System.out.println("\t"+valueIterator.next());
}
}
String inputLine;
DataInputStream input = new DataInputStream(connection.getInputStream());
System.out.println("BODY CONTENT");
System.out.println("-------------------------------");
while ((inputLine = input.readLine()) != null) {
System.out.println(inputLine);
}
} catch (MalformedURLException e) {
System.err.println(e);
} catch (IOException e) {
e.printStackTrace();
}
}
}
EDIT I've just recieved confirmation that this works on java 1.5

Related

TLS on apache server

I want to start Apache HTTP server in Java.
After a while I found this answer. And did as indicated there.
The KeyStore was created according to this instruction.
My code now:
import me.project.Main;
import org.apache.http.ExceptionLogger;
import org.apache.http.config.SocketConfig;
import org.apache.http.impl.bootstrap.HttpServer;
import org.apache.http.impl.bootstrap.ServerBootstrap;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
public class Server {
private static final Logger logger = LoggerFactory.getLogger(Server.class);
private static HttpServer server;
public static void createAndStart() {
if (server != null) return;
SSLContext sslContext = prepareSSLContext();
SocketConfig config = SocketConfig.custom().setSoTimeout(1500).setTcpNoDelay(true).build();
server = ServerBootstrap.bootstrap()
.setListenerPort(43286)
.setServerInfo("Test")
.setSocketConfig(config)
.setSslContext(sslContext)
.setExceptionLogger(ExceptionLogger.STD_ERR)
.registerHandler("/", new HelloPage())
.create();
System.out.println("Ok");
try {
server.start();
} catch (IOException ioException) {
logger.error("Cannot start server: ", ioException);
}
}
private static SSLContext prepareSSLContext() {
URL keyStoreFile = Main.class.getClassLoader().getResource("keystore.jks");
if (keyStoreFile == null) {
logger.error("Key store not found");
System.exit(1);
}
SSLContext sslContext = null;
try {
sslContext = SSLContexts.custom()
.loadKeyMaterial(keyStoreFile, "mysuperpass".toCharArray(), "mysuperpass".toCharArray()).build();
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | UnrecoverableKeyException | CertificateException | IOException e) {
logger.error("Cannot init ssl context", e);
}
return sslContext;
}
}
It starts sucessfully and prints "Ok".
But a few things I still don't understand:
It seems to me that this is still SSL protocol, not TLS
How can I make sure that the server really communicates using the encrypted TLS protocol (except to intercept traffic and watch)
How does the loadKeyMaterial (keyStore, storePass, KeyPass) method know which key to take from the store without the key alias?
I found another example of enabling TLS here, but I don't understand where to use the object conn after:
DefaultBHttpClientConnection conn = new DefaultBHttpClientConnection(8 * 1204);
conn.bind(socket);
Sorry, I don't know English well and translated this with Google Translate
It seems to me that this is still SSL protocol, not TLS
The classes were originally implemented for SSL(v3) in the 1990s, but they have implemented TLS since about 2000 (first 1.0, later 1.1 1.2 and now 1.3) while the names have remained the same for compatibility. In fact since 8u31 in 2014 SSLv3 has been disabled by default in the JVM configuration because it was broken by the "POODLE" attack and the 'SSL' classes in fact provide only TLS.
How can I make sure that the server really communicates using the encrypted TLS protocol (except to intercept traffic and watch)
Try connecting to it with TLS and non-TLS tools.
How does the loadKeyMaterial (keyStore, storePass, KeyPass) method know which key to take from the store without the key alias?
It uses the JSSE-default KeyManager which implements chooseServerAlias to return the first key-and-cert entry (i.e. PrivateKeyEntry) it finds that is suitable for a client-enabled ciphersuite -- or for TLS 1.3 where this is no longer in the ciphersuite, a client-enabled sigalg. IIRC 'first' is in a hashmap-defined order which means for practical/human purposes it is arbitrary. But most servers use a keystore that contains only one PrivateKeyEntry so all choice sequences are the same.

SSL exception in JAVA6 but no in JAVA8

Hy
I try to connect a java program to an REST API.
With the same part of code I have a Java Exception in Java 6 and it works fine in Java 8.
It's the same environment :
trustore
machine
unix user
the code :
import java.io.DataInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class MainClass {
public static void main (String[] args){
String serviceUrl = "https://api.domain.com" + "/endpont/path";
try {
URL url = new URL(serviceUrl);
URLConnection connection = null;
try{
connection = url.openConnection();
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Content-Type", "application/json");
String body = "";
String inputLine;
DataInputStream input = new DataInputStream (connection.getInputStream());
while (((inputLine = input.readLine()) != null)){
body += inputLine;
}
System.out.println(body);
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
the error in Java 6 : sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Somebody know how it's different ? Can I use some tricks to have the same result in Java 6 ?
The CN of the cert is a wildcard : "*.domain.com" . It can be the cause ?
I tried several api but there all used the sun SSL layer. Do you know an other to replace it ?
JRE has it's own keystore, where certificates can be stored. Maybe your JDK/JRE for Java 6 has different keys than Java 8.

Cannot access azure blobs through rest api

I was able to create a Container in Storage Account and upload a blob to it through the Client Side Code.
I was able to make the blob available for Public access as well , such that when I hit the following query from my browser, I am able to see the image which I uploaded.
https://MYACCOUNT.blob.core.windows.net/MYCONTAINER/MYBLOB
I now have a requirement to use the rest service to retrieve the contents of the blob. I wrote down the following java code.
package main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class GetBlob {
public static void main(String[] args) {
String url="https://MYACCOUNT.blob.core.windows.net/MYCONTAINER/MYBLOB";
try {
System.out.println("RUNNIGN");
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestProperty("Authorization", createQuery());
connection.setRequestProperty("x-ms-version", "2009-09-19");
InputStream response = connection.getInputStream();
System.out.println("SUCCESSS");
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(response));
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static String createQuery()
{
String dateFormat="EEE, dd MMM yyyy hh:mm:ss zzz";
SimpleDateFormat dateFormatGmt = new SimpleDateFormat(dateFormat);
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC"));
String date=dateFormatGmt.format(new Date());
String Signature="GET\n\n\n\n\n\n\n\n\n\n\n\n" +
"x-ms-date:" +date+
"\nx-ms-version:2009-09-19" ;
// I do not know CANOCALIZED RESOURCE
//WHAT ARE THEY??
// +"\n/myaccount/myaccount/mycontainer\ncomp:metadata\nrestype:container\ntimeout:20";
String SharedKey="SharedKey";
String AccountName="MYACCOUNT";
String encryptedSignature=(encrypt(Signature));
String auth=""+SharedKey+" "+AccountName+":"+encryptedSignature;
return auth;
}
public static String encrypt(String clearTextPassword) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(clearTextPassword.getBytes());
return new sun.misc.BASE64Encoder().encode(md.digest());
} catch (NoSuchAlgorithmException e) {
}
return "";
}
}
However , I get the following error when I run this main class...
RUNNIGN
java.io.IOException: Server returned HTTP response code: 403 for URL: https://klabs.blob.core.windows.net/delete/Blob_1
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
at main.MainClass.main(MainClass.java:61)
Question1: Why this error, did I miss any header/parameter?
Question2: Do I need to add headers in the first place, because I am able to hit the request from the browser without any issues.
Question3: Can it be an SSL issue? What is the concept of certificates, and how and where to add them? Do I really need them? Will I need them later, when I do bigger operations on my blob storage(I want to manage a thousand blobs)?
Will be thankful for any reference as well, within Azure and otherwise that could help me understand better.
:D
AFTER A FEW DAYS
Below is my new code for PutBlob I azure. I believe I have fully resolved all header and parameter issues and my request is perfect. However I am still getting the same 403. I do not know what the issue is. Azure is proving to be pretty difficult.
A thing to note is that the containers name is delete, and I want to create a blob inside it, say newBlob. I tried to initialize the urlPath in the code below with both "delete" and "delete/newBlob".
Does not work..
package main;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class Internet {
static String key="password";
static String account="klabs";
private static Base64 base64 ;
private static String createAuthorizationHeader(String canonicalizedString) throws InvalidKeyException, Base64DecodingException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(base64.decode(key), "HmacSHA256"));
String authKey = new String(base64.encode(mac.doFinal(canonicalizedString.getBytes("UTF-8"))));
String authStr = "SharedKey " + account + ":" + authKey;
return authStr;
}
public static void main(String[] args) {
System.out.println("INTERNET");
String key="password";
String account="klabs";
long blobLength="Dipanshu Verma wrote this".getBytes().length;
File f = new File("C:\\Users\\Dipanshu\\Desktop\\abc.txt");
String requestMethod = "PUT";
String urlPath = "delete";
String storageServiceVersion = "2009-09-19";
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:sss");
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = fmt.format(Calendar.getInstance().getTime()) + " UTC";
String blobType = "BlockBlob";
String canonicalizedHeaders = "x-ms-blob-type:"+blobType+"\nx-ms-date:"+date+"\nx-ms-version:"+storageServiceVersion;
String canonicalizedResource = "/"+account+"/"+urlPath;
String stringToSign = requestMethod+"\n\n\n"+blobLength+"\n\n\n\n\n\n\n\n\n"+canonicalizedHeaders+"\n"+canonicalizedResource;
try {
String authorizationHeader = createAuthorizationHeader(stringToSign);
URL myUrl = new URL("https://klabs.blob.core.windows.net/" + urlPath);
HttpURLConnection connection=(HttpURLConnection)myUrl.openConnection();
connection.setRequestProperty("x-ms-blob-type", blobType);
connection.setRequestProperty("Content-Length", String.valueOf(blobLength));
connection.setRequestProperty("x-ms-date", date);
connection.setRequestProperty("x-ms-version", storageServiceVersion);
connection.setRequestProperty("Authorization", authorizationHeader);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
System.out.println(String.valueOf(blobLength));
System.out.println(date);
System.out.println(storageServiceVersion);
System.out.println(stringToSign);
System.out.println(authorizationHeader);
System.out.println(connection.getDoOutput());
DataOutputStream outStream = new DataOutputStream(connection.getOutputStream());
// Send request
outStream.writeBytes("Dipanshu Verma wrote this");
outStream.flush();
outStream.close();
DataInputStream inStream = new DataInputStream(connection.getInputStream());
System.out.println("BULLA");
String buffer;
while((buffer = inStream.readLine()) != null) {
System.out.println(buffer);
}
// Close I/O streams
inStream.close();
outStream.close();
} catch (InvalidKeyException | Base64DecodingException | NoSuchAlgorithmException | IllegalStateException | UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I know only a proper code reviewer might be able to help me, please do it if you can.
Thanks
Question1: Why this error, did I miss any header/parameter?
Most likely you're getting this error is because of incorrect signature. Please refer to MSDN documentation for creating correct signature: http://msdn.microsoft.com/en-us/library/azure/dd179428.aspx. Unless your signature is correct you'll not be able to perform operations using REST API.
Question2: Do I need to add headers in the first place, because I am
able to hit the request from the browser without any issues.
In your current scenario, because you can access the blob directly (which in turn means the container in which the blob exist has Public or Blob ACL) you don't really need to use REST API. You can simply make a HTTP request using Java and read the response stream which will have blob contents. You would need to go down this route if the container ACL is Private because in this case your requests need to be authenticated and the code above creates an authenticated request.
Question3: Can it be an SSL issue? What is the concept of
certificates, and how and where to add them? Do I really need them?
Will I need them later, when I do bigger operations on my blob
storage(I want to manage a thousand blobs)?
No, it is not an SSL issue. Its an issue with incorrect signature.
Finally found the mistake!!
In the code above , I was using a String "password" as key for my SHA2
base64.decode(key)
It should have been the key associated with my account with AZURE.
Silly One!! Took me 2 weeks to find.

How to check if proxy is working in Java?

I searched google, this site and JavaRanch and I can not find an answer.
My program needs to obtain proxies from a selected file(I got that done using java gui FileChooser class and RandomAccessFile)
Then I need to verify the proxies starting with the one that is first in the txt file. It will try to connect to some site or port to verify if the connection was successful.If the connection was successful (I got a positive response) it will add the proxy to a list of proxies and then get and check next one in the list until it is done.
I know how to do this but I got a little problem. My Problem is that this process needs to be independent of connection speed because someone may set 15000(milliseconds) timeout for the connection to be dealt with and set 100 threads and then none of the proxies would come out working because connection is too slow.
I heard of a method called pinging to check proxies,but I do not know how to use it in java.
Could anyone give me solution or at least classes I could use.
Ok I found a solution and it is easy.
What I used it InetAddress.isReachable() method along with some HttpClient by Apache. For proxy checking I used blanksite.com because all I need is check connectability and not speed of proxies.
So here is the code(Including input from file, but it is not gui, YET):
/* compile with
java -cp .;httpclient-4.5.1.jar;httpcore-4.4.3.jar ProxyMat
run with
java -cp .;httpclient-4.5.1.jar;httpcore-4.4.3.jar;commons-logging-1.2.jar ProxyMat
put one proxy to check per line in the proxies.txt file in the form
some.host.com:8080
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
public class ProxyMat{
File file=null;
static RandomAccessFile read=null;
public ProxyMat(){
file=new File("proxies.txt");
try {
read=new RandomAccessFile(file,"rw");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public void checkproxies(){
try{
String line;
for(int i=0;i<25;i++){
if((line=read.readLine())!=null){
System.out.println(line);
String[] hp=line.split(":");
InetAddress addr=InetAddress.getByName(hp[0]);
if(addr.isReachable(5000)){
System.out.println("reached");
ensocketize(hp[0],Integer.parseInt(hp[1]));
}
}
}
}catch(Exception ex){ex.printStackTrace();}
}
public void ensocketize(String host,int port){
try{
File pros=new File("working.txt");
HttpClient client=new DefaultHttpClient();
HttpGet get=new HttpGet("http://blanksite.com/");
HttpHost proxy=new HttpHost(host,port);
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 15000);
HttpResponse response=client.execute(get);
HttpEntity enti=response.getEntity();
if(response!=null){
System.out.println(response.getStatusLine());
System.out.println(response.toString());
System.out.println(host+":"+port+" ## working");
}
}catch(Exception ex){System.out.println("Proxy failed");}
}
public static void main(String[] args){
ProxyMat mat=new ProxyMat();
mat.checkproxies();
}
}

Detecting Windows/IE proxy setting using Java

I need to automatically detect if a user requires a proxy to access the internet. Is there a way for a Java application to read the systems proxy setting?
Thanks,
Jimmy
Java SE 1.5 provides ProxySelector class to detect the proxy settings. If there is a Direct connection to Internet the Proxy type will be DIRECT else it will return the host and port.
Example below illustrates this functionality:
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
public class TestProxy {
public static void main(String[] args) {
try {
System.setProperty("java.net.useSystemProxies","true");
List<Proxy> l = ProxySelector.getDefault().select(
new URI("http://www.yahoo.com/"));
for (Iterator<Proxy> iter = l.iterator(); iter.hasNext(); ) {
Proxy proxy = iter.next();
System.out.println("proxy hostname : " + proxy.type());
InetSocketAddress addr = (InetSocketAddress)proxy.address();
if(addr == null) {
System.out.println("No Proxy");
} else {
System.out.println("proxy hostname : " + addr.getHostName());
System.out.println("proxy port : " + addr.getPort());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
The other, accepted, answer is undoubtedly excellent and correct but I thought I would add something here...
If you are on a machine that is configured with "auto detect proxy settings", which I believe is called PAC, the code to detect the proxy in the answer using the Java gubbins will not work (it will think it is a "direct" connection).
There is a library called proxy vole (new BSD license I think), however, that you can use instead so here's the other answer's code slightly modified to use that:
public class testProxy {
public static void main(String[] args) {
try {
System.setProperty("java.net.useSystemProxies","true");
// Use proxy vole to find the default proxy
ProxySearch ps = ProxySearch.getDefaultProxySearch();
ps.setPacCacheSettings(32, 1000*60*5);
List l = ps.getProxySelector().select(
new URI("http://www.yahoo.com/"));
//... Now just do what the original did ...
for (Iterator iter = l.iterator(); iter.hasNext(); ) {
Proxy proxy = (Proxy) iter.next();
System.out.println("proxy hostname : " + proxy.type());
InetSocketAddress addr = (InetSocketAddress)
proxy.address();
if(addr == null) {
System.out.println("No Proxy");
} else {
System.out.println("proxy hostname : " +
addr.getHostName());
System.out.println("proxy port : " +
addr.getPort());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
It needs these imports:
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
import com.btr.proxy.search.ProxySearch;
Oh, and there're usage examples for proxy vole here.

Categories