I inherited some code, no clue what it's trying to do (I commented what i think its doing), the original coder left my organization years ago... I'm hoping the great community here can at least point me in some direction as to what this code might be trying to do, and where I can start looking for a solution...
Java code
//Read java.security file from JDK and create a Security provider from it
PropertyFileReader reader = new PropertyFileReader();
Security.addProvider(new IBMJSSEProvider());
Security.setProperty("ssl.SocketFactory.provider",
"com.ibm.jsse2.SSLSocketFactoryImpl");
System.getProperties().putAll(
reader.readProperties("security.properties"));
//Set some authentication stuff
Authenticator.setDefault(new PasswordAuthentication("User", "Password"));
// get url to servlet (note, actual application has valid url)
url = new URL("Connection URL");
// Set out HTTP URL connection
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestProperty("Authorization", "Basic ");
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
httpURLConnection.setUseCaches(false);
httpURLConnection.setDefaultUseCaches(false);
httpURLConnection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
httpURLConnection.setRequestMethod("POST");
//EXCEPTION IS THROWN HERE!
DataOutputStream outputStream = new DataOutputStream(
httpURLConnection.getOutputStream());
Stack trace
javax.net.ssl.SSLKeyException: RSA premaster secret error
at com.ibm.jsse2.fb.<init>(fb.java:38)
at com.ibm.jsse2.hb.a(hb.java:200)
at com.ibm.jsse2.hb.a(hb.java:70)
at com.ibm.jsse2.gb.n(gb.java:223)
at com.ibm.jsse2.gb.a(gb.java:170)
at com.ibm.jsse2.sc.a(sc.java:595)
at com.ibm.jsse2.sc.g(sc.java:284)
at com.ibm.jsse2.sc.a(sc.java:200)
at com.ibm.jsse2.sc.startHandshake(sc.java:205)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsU RLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1014)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.jav a:230)
What kind of connection is this considered?
What the heck is a RSA Premaster Secret?
What / Where should I start looking / studying to understand whats going on?
Thanks!
I had a similar issue today with our web app. The guys in system admin room updated the Java version without asking anyone. After hours of searching i found something useful.
Here is the link if you are still interested:
https://community.oracle.com/thread/1533888
The solution: Just remove the updated java version from your server Classpath and try to install the old java version.
similar question in Stackoverflow:
SSL IOExceptionjavax.net.ssl.SSLKeyException: RSA premaster secret error
Related
Currently I'm trying to address a webserver using HTTPS and POST method and send a JSON file to this server. I have already tried several tutorials but unfortunately I can only find examples for HTTP and Post and not HTTPS. Did I forget to implement something?
I would like to provide the code of the server, but I only received the address and the format of the JSON files.
Has anyone had the problem before or can help me?
Thank you
public static void main(String[] args) throws IOException {
URL url = new URL(" https://webservice.com:1234");
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json; utf-8");
con.setRequestProperty("Accept", "application/json");
//con.setDoInput(true);
con.setDoOutput(true);
String jsonInputString = "\"ID\": \"12\"";
System.out.println(jsonInputString);
try(OutputStream os = con.getOutputStream()) {
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
os.flush();
}
System.out.println(con.getResponseCode());
Unfortunately I always get this error message:
Exception in thread "main" javax.net.ssl.SSLException: Unsupported or
unrecognized SSL message at
java.base/sun.security.ssl.SSLSocketInputRecord.handleUnknownRecord(SSLSocketInputRecord.java:439)
at
java.base/sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:184)
at
java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:108)
at
java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1180)
at
java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1091)
at
java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
at
java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:567)
at
java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:187)
at
java.base/sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1362)
at
java.base/sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1337)
at
java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:247)
at test.main(test.java:40)
Process finished with exit code 1
Sometimes the https returns SSL errors if the service is not secure. This happens a lot in localhost or some servers with only http. Maybe try removing the 's'
Many thanks for all your help, in a discussion with the developer of the web service I was able realize that the server does not support HTTPS. That means the link to the server was wrong - http//: instead of https//:
So with the HttpURLConnection con = (HttpURLConnection)url.openConnection(); it works just fine.
Context: I'm receiving a 400 error when attempting to get a crumb from a Jenkins CI server via Java's HttpsURLConnection class. A Python utility that I wrote makes the call successfully with no problems, as does wget. Here's the Java code:
String crumb_url = JENKINS_URL + "crumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)";
String userpass = config.getProperty("USERNAME") + ":" + config.getProperty("API_TOKEN");
String basicAuth = "Basic " + javax.xml.bind.DatatypeConverter.printBase64Binary(userpass.getBytes());
URL url = new URL(crumb_url);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(sslFactory);
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", basicAuth);
conn.setRequestProperty("User-Agent", "XXXXXXXXXX/1.0");
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
The call to create the BufferedReader is where I get an IOException indicating that I got a 400 from the server. Since I'm getting a 400 instead of a certificate-related exception, I'm pretty sure the SSL stuff is working properly. I turned on debug info to see exactly what was being sent, and this is what it's telling me:
HTTPS GET header
Sorry about redacting some of the info, but it shouldn't be relevant. My main concern is the 16 bytes highlighted at the beginning of the request, and that the extra data may be why the Jenkins server is unhappy. Otherwise, the request looks practically identical to what wget sends, with the exception of "Keep-Alive" in wget vs. "keep-alive" in Java. I also attempted to generate the request by hand in case the capitalization difference was the problem, but I still get the 16 byte prefix before the GET. I'm also somewhat curious about the trailing data after the request, but I suspect as long as I have the two CR/LFs at the end it shouldn't matter.
If anyone has any ideas on how to resolve this, I'm all ears. Thanks.
I can address your 'main concern' but not your problem :-(
Padded plaintext before ENCRYPTION strongly suggests this was captured inside your TLS stack, since you're using Java probably by javax.net.debug. When TLS sends application data, which for HTTPS is the HTTP request or response, it adds several things depending on the protocol and ciphersuite in use. For an AES (or possibly but much less common Camellia SEED or ARIA) CBC cipher in TLS 1.1 or 1.2, it adds a 16-byte IV at the beginning, and an HMAC and padding at the end. The data at the end of your screenshot after the double-CRLF is valid for a TLS CBC 'GenericBlock' record if the selected HMAC is SHA384, which it might be since you didn't say which ciphersuite was used.
However, that means the request you are actually sending at the app level looks valid, which doesn't help with your 400.
Although, /:, in your query part are in the RFC2396 reserved set and " is excluded which are supposed to be percent-encoded. Webservers and apps vary wildly in how they handle this, and I have no idea if Jenkins cares.
The percent-encoding of the URL was the problem. Thanks to all that answered!
I admit there is a possibility that I am not well informed about the subject, but I've done a LOADS of reading and I still can't get answer to my question.
From what I have learnt, to make communication secure with HTTPS I need to be using some sort of public key (reminds me of pgp-encryption).
My goal is to make a secured POST request from my java application (which I, in the moment it starts working, will rewrite to Android app, if it matters) to a php application accessible via https address.
Naturally I did some Google research on the topic and I got a lot of results how to make ssl connection. Non of those results used any sort of certificate/hash prints. They just use HttpsURLConnection instead of HttpURLConnection, everything else is almost identical.
Right now, almost copy paste of something I found here is this:
String httpsURL = "https://xx.yyyy.zzz/requestHandler.php?getParam1=value1&getParam2=value2";
String query = "email=" + URLEncoder.encode("abc#xyz.com", "UTF-8");
query+="&";
query+="password="+URLEncoder.encode("tramtarie","UTF-8");
URL myurl = new URL(httpsURL);
HttpsURLConnection con = (HttpsURLConnection) myurl.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-length",String.valueOf(query.length()));
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)");
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(query);
output.close();
DataInputStream input = new DataInputStream(con.getInputStream());
for(
int c = input.read();
c!=-1;c=input.read())
System.out.print((char)c);
input.close();
System.out.println("Resp Code:"+con.getResponseCode());
System.out.println("Resp Message:"+con.getResponseMessage());
Which sadly does not work and ends up with this exception:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching app.elessy.cz found
This probably means that it checks the certificate and finds out that the certificate I am using does not match domain name for which is registered (it is webhosting certificate, registered for webhosting domain, not the domain I own, the only reason I am using https is to secure data for internal purposes, I do not want this site to be visited by users from outside, so this certificate should be ok).
There are two things that I just don't get about the code and everything.
No code I have been able to find use MD5/SHA-1 (supposedly the public keys for message encryption?) prints or
certificate, they just somehow automatically connect to https
website and should work. Doesn't work for me though.
Do I really need those md5/sha-1 prints that are provided to me? Or at least, what in the given context do those prints mean?
Edit:
Following the given answer and duplicate mark, I managed to get it working - in the meaning that I can communicate with application behind https.
But I didnt have to use any sort of md5/sha1 print. How do I know now that it is safe? Does this protocol on his own? Like that communication is secured either way, when I use built-in java classes to connect to app behind https?
I probably do not seek for precise technical explanation, but more for an assurance that yes - the communication is safe even though I do not use (knowingly) certificate/servers public key to encrypt my messages. That it does the ssl connection for me.
This question already has answers here:
Trusting all certificates using HttpClient over HTTPS
(22 answers)
Closed 8 years ago.
I'm trying to hit an https site through an Android client:
URL url = new URL(myurl);
Log.d("Connection", myurl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.addRequestProperty("Content-Type", "application/json");
conn.setRequestMethod("POST");
conn.setDoInput(true);
// Starts the query
Log.d("Connection", "Connecting...");
conn.connect();
The connect call is throwing an exception:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
EDIT: I'm told the site is using a self-signed certificate, and since this is only a prototype I just need to trust all hosts so it will work. Can someone point me toward a simple example of doing this? The code I've seen online gets quite complicated, I just want to do a hacky bypass of any verification.
Are you sure that the password you are supplying is correct? This answer suggests that the connection can appear to hang if the password is incorrect.
I fixed it by creating a new .csr with the right Organizational Unit Name and Common Name
Hope you are using HTTPS in your URL.
I made an app. for Android which uses the C2DM service from Google. I
made a server simulator from some tutorials and it works fine. My
problem is, I tried to build a Java Servlet. From the Android device
it receives fine the message and saves the Registration ID, but when I
try to send a https POST request to the Google C2DM Server it always
gets a SocketTimeoutException : Timeout while fetching:
https://android.clients.google.com/c2dm/send.
I don't get why this is happening when the same works on the Android
device. Here is the code:
//The AuthToken from Google Client Login
String auth_key = TOKEN;
StringBuilder postDataBuilder = new StringBuilder();
//some parameters to pass, I've checked and it's correct, it's working
//with Fiddler
postDataBuilder.append(PARAM_REGISTRATION_ID).append("=").append(REGISTRATION_ID);
postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=").append("0");
postDataBuilder.append("&").append("data.payload").append("=").append(URLEncoder.encode(message, UTF8));
byte[] postData = postDataBuilder.toString().getBytes(UTF8);
URL url = new URL("https://android.clients.google.com/c2dm/send");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
conn.setRequestProperty("Content-Length",Integer.toString(postData.length));
conn.setRequestProperty("Authorization", "GoogleLogin auth="+auth_key);
OutputStream out = conn.getOutputStream();
out.write(postData);
out.close();
int responseCode = conn.getResponseCode();
//here comes the error processing, but I can't reach it, because of
//the exception.
if (responseCode == 401 || responseCode == 403) {
//....
}
Thanks for your help :).
The first obvious thing to check is - if you have thought of this I apologise - are you behind a proxy server e.g. a company firewall? If so a timeout is exactly the symptom I'd expect with the above code. (This catches me out all the time!)
With the latter half of your code (from the HttpURLConnection declaration on), unmodified, I see a timeout; on my system (behind a company firewall), with two changes I get a 200 OK back:
addition of a proxy object passed to the HttpUrlConnection factory as follows:
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("...", 8080));
HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
accepting the C2DM server's certificate that wasn't trusted by my JVM. For test purposes I overrode the default hostname verifier and TrustManager as described in Trusting all certificates using HttpClient over HTTPS . For production you should look at a more secure solution.
Another thing I spotted; it doesn't seem to matter but http://code.google.com/android/c2dm/index.html#push says to post to https://android.apis.google.com/c2dm/send, not android.clients.google.com - just something to be aware of that might break in future.
I faced same problem and
I had tried :
URL url = new URL("http://android.apis.google.com/c2dm/send");
instead of :
URL url = new URL("https://android.apis.google.com/c2dm/send");
it worked for me.