Accessing URL from Java requiring certificate [duplicate] - java

This question already has answers here:
How to convert .pfx file to keystore with private key?
(7 answers)
Closed 5 years ago.
I am fairly ignorant regarding certificates, and would appreciate any guidance as to what I do wrong... Unfortunately I wasn't able to find a solution on the rest of StackOverflow or elsewhere on the web.
I have a URL (using HTTPS) from which I should get the response. (An image in my case, but I'm sure that's less important.)
Here's what I did:
1. Accessing URL from web browser
It response with HTTP code 403 "Forbidden".
I am given a certificate (*.pfx file) which is needed to access the URL.
2. Installing certificate and trying again from browser
Double-clicking on the PFX file opens the "Certificate Import Wizard" (Windows 10). Follow along, then reboot.
Now Chrome retrieves the resource fine.
Firefox still shows a 403, so under Options > Advanced > Certificates > View Certificates I import the PFX. Now FF also returns the resource fine.
3. Installing certificate under JVM
I now want to call the same URL using Java. I'm still on Java 7 for this project for legacy purposes. I understand the cert should be imported into the Java keystore using the keytool CLI command. However this command wants a cert in DER X509 format. So I export the cert again from Chrome into this format.
Now run the command: keytool -import -alias MY_ALIAS -keystore C:/PROGRA~1/Java/jdk1.7.0_80/jre/lib/security/cacerts -file my_cert.cer
Do keytool -list -v -keystore C:/PROGRA~1/Java/jdk1.7.0_80/jre/lib/security/cacerts and inspect for inclusion of required cert.
Now I run my Java program:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
public class TestUrlRead {
private static final String PROXY_URL = ...;
private static final int PROXY_PORT = ...;
private static final String IMAGE_URL = ...;
public static void main(String[] args) throws Exception {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_URL, PROXY_PORT));
URL url = new URL(IMAGE_URL);
URLConnection con = url.openConnection(proxy);
con.setDoOutput(true);
con.connect();
InputStream webIn = con.getInputStream(); // <-- causes IOException
// read and use webIn
inReader.close();
}
}
The exception thrown is:
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 403 for URL: ...
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1627)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at TestUrlRead.main(TestUrlRead.java:33)
The response and timing suggest that this is similar to the browser without certificate. What am I doing wrong?

I export the cert again from Chrome into this format.
At this point you lost the private key that was contained in the .pfx file, so you were unable to send a certificate to the server. You should have imported the .pfx file directly as a keystore of its own, type PKCS12, or indeed just use it directly via javax.net.ssl.keyStore/keyStoreType/keyStorePassword. See this question for how to do that.

Related

WsImport unable to find imported certificate

Apologies for yet another "unable to find certificate" question.
I'm developing on a Windows 7 machine. I am using multiple Java versions and because of that am explicit about paths to the used java version (here Java6). I achieve this by the following two lines:
set path=c:\Program Files\Java\jdk1.6.0_45\bin;%path%
set java_home=c:\Program Files\Java\jdk1.6.0_45
I need to use a 3rd party web service https://service.gov/Service.svc?wsdl that provides a certificate.PFX certificate (both service URI and certificate file are renamed as a way to protect the 3rd party's interests). I have made sure that after importing the certificate file in Windows I can open the WSDL file in my browser.
I first import the certificate in my keystore (using Administrator Command Prompt to get access to write in the system folder):
keytool -importkeystore -srckeystore certificate.pfx -srcstoretype pkcs12 -keystore "c:\Program Files\Java\jdk1.6.0_45\jre\lib\security\cacerts"
I get a success notification. Still, I make sure that the new certificate is present in the output of:
keytool -list -keystore "c:\Program Files\Java\jdk1.6.0_45\jre\lib\security\cacerts"
Then I create a new folder containing blank subfolders called src and classes. Once this is done, I run wsimport from that new folder (using Java class instead of binary to make sure I am explicit about the truststore being used):
java -classpath "c:\Program Files\Java\jdk1.6.0_45\lib\tools.jar" -Djavax.net.ssl.trustStore="c:\Program Files\Java\jdk1.6.0_45\jre\lib\security\cacerts" -Djavax.net.ssl.trustStorePassword=changeit com.sun.tools.internal.ws.WsImport https://service.gov/Service.svc?wsdl -s src -d classes
The output is the following:
parsing WSDL...
[ERROR] sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Failed to read the WSDL document: https://service.gov/Service.svc?wsdl, because 1) could not find the document; /2) the document could not be read; 3) the root element of the document is not <wsdl:definitions>.
[ERROR] failed.noservice=Could not find wsdl:service in the provided WSDL(s):
At least one WSDL with at least one service definition needs to be provided.
Failed to parse the WSDL.
The WSDL file contains and is used by other organisations, so the problem is pretty certainly not on the 3rd party's side.
Am I missing something? To me it all seems obvious by now, but it still doesn't work. I have also tried this with Java8, and the result is pretty much the same. The only difference is that in Java8, the WsImport class no longer exists, so I am using the wsimport.exe binary.
Thanks in advance for any ideas or hints.
The pfx file (which contains a certificate and also a private key) is for client authentication, while a truststore is for validating the server certificate. It is important to understand the difference between a keystore and a truststore.
You have imported the client certificate (and key) into the default truststore (cacerts). What you should have done instead is:
Import the issuer (CA) of the SSL certificate of the server into cacerts. You can skip this step if the CA certificate is already in cacerts, which is probably the case here.
Use the pfx file as your keystore for client authentication. The easiest way is to convert it to jks: https://stackoverflow.com/a/3054034/2672392 The properties to pass to wsimport are "javax.net.ssl.keyStore" and "javax.net.ssl.keyStorePassword".
See this answer for a list of important SSL properties: https://stackoverflow.com/a/5871352/2672392

How to read browsers certificates uisng java on linux? by using keyStore.getInstance("xyz")

Am trying to read the installed certificates by using code
KeyStore ks = KeyStore.getInstance("Windows-MY")
ks.load(null, null)
Enumeration<String> enumeration = ks.aliases()
while (enumeration.hasMoreElements()) {
String string = (String) enumeration.nextElement()
System.out.println(string)
}
this code list out the installed certificates on windows but on linux doesn't? tried by changing the keystore providers also.
I'm not sure what you mean with "read browsers certificates".
Are you trying to read certificates from the default Java keystore? What's your goal?
KeyStore.getInstance(..) instantiates a keystore with a specific type (JKS, for example). When you want to read from a specific keystore, you need to specify the path to the keystore and make the KeyStore instance load that file.
See http://www.java2s.com/Code/Java/Security/RetrievingaKeyPairfromaKeyStore.htm for an example and https://docs.oracle.com/javase/8/docs/api/java/security/KeyStore.html for more details.
Edited: updated answer after clarified question.
You can find more info on reading browser keystores in Linux on:
http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/keystores.html
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/JSS
applet with SunMSCapi not working in linux
http://forums.mozillazine.org/viewtopic.php?p=12037571
Try with libsoftokn3.so of NSS.
See my answer here, "Approach 1".
The key is to find where libsoftokn3.so is, and use it as the libfile to construct a config file, and then a KeyStore.
You can get the Default Type.
Try the below code
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

access denied ("java.io.FilePermission" "execute")

I am beginner.it is first applet that i writing
i want run exe application with applet
java code
package appletexample;
import java.io.*;
import java.awt.*;
import java.applet.Applet;
public class Welcome extends Applet {
public void init() {
String execommand = "C:\\windows\\notepad.exe" ;
try {
Process proc = Runtime.getRuntime().exec(execommand) ;
}
catch(IOException ieo) {
System.out.println("Problem starting " + execommand) ;
}
}
}
java.policy.applet
grant {
permission java.security.AllPermission;
};
i run this code in eclipse Run As->Java Applet worked and opened NotePade
but when Export->Jar File(with .classPath,.project,java.policy.applet)
and use in
Html
<applet archive="test.jar" code="appletexample/Welcome.class" width=550 height=300>
in firefox say error access denied ("java.io.FilePermission" "execute")?
how can fix this problem?
download my java and Html code
I assume that you just want to practice how to write a applet.
For development purpose, you can create a keystore and then use it to sign your applet.jar.
Go: Start Menu > Execute > cmd.exe
Input:
cd /
keytool -genkey -dname "cn=CN, ou=OU, o=O, l=L, st=ST, c=C" -alias mykey -keypass mypass -keystore mystore -validity 3650 -storepass mypass
jarsigner -keystore c:\mystore -storepass mypass C:\path\to\applet.jar mykey
Then:
Refresh your HTML page.
As beginner you should start with something much much simpler. When you play with Applets not all security rules apply. But when you come to real world (Browser in your case or, in other terms, sandbox) security rules are in force to prevent your code from harming the host computer.
What you are doing - you are running some program on the client computer when the client opens your web page with an Applet. That what viruses do. People will not want to allow it.
Of course you can the use Signed Applet approach or other ways to run program on another computer, but is it your goal? If it is to learn basics, then run easy stuff. Eventually, you will understand JNLP (Java Web Start) and other methods useful for you and your clients.

Install a renewed SSL certificate in Tomcat

I successfully installed a GoDaddy SSL certificate in Tomcat last year.
When the certificate expired, I renewed it. I did this without generating a new keystore or CSR. GoDaddy delivered three files to me, gd_bundle.crt, gd_intermediate.crt, and a third .crt file with a random number as the name.
I don't know what to do next. I assume I have to incorporate these files into my existing keystore. GoDaddy provides this help page:
http://support.godaddy.com/help/article/5355/ssl-certificate-renewal-tomcat-4-x5-x6-x
The page says I can do this one of two ways. I tried the first way and all I got was an error message saying "-inkey: no such file or directory". I tried the second way, but I do not have any file with the name it references, and also any attempt to import the new certs into the existing keystore results in an error "certificate not imported, alias already exists".
What is the correct way to update my keystore file with the new certificate?
Thanks.
You need to use the keytool to import the numbered file into the existing KeyStore, using the same alias you're already using, with the -importcert option.

Java and SSL certificates

I am trying to establish a connection with a PHP script of mine in Java using the secure socket layer (HTTPS), but I have found out that to ensure maximum security/validity I have to import the SSL certificate that my website uses into my application... Something I don't know how to do.
If it helps, my SSL Certificate is not self signed, rather provided by StartSSL AND I am using Eclipse IDE.
Could anybody point me in the right direction? i.e. What files do I need, where should I import them and what code do I need in Java, etc?
I have found out that to ensure maxium security/validity I have to import the SSL certificate that my website uses into my application
You are partially right when you make that statement. You do not need to import your SSL certificate. It is sufficient that the StartSSL CA certificate be imported.
Additionally, there is no such thing as importing a certificate into a Java application. SSL support in Java relies on the concept of keystores and truststores, and not on some certificate packaged within your application. If you are publishing your application to be downloaded and executed by end-users, there is no need for your to publish your certificate or for that matter your private key in your application. The private key, and the associated certificate would be stored in a keystore, that only you may access.
The end-users of your application would rely on the SSL support within the Java runtime, that would enable the application to establish SSL connections to sites, after the server-certificate is verified. The Java runtime ships with a default set of CA certificates in a truststore, and the only prerequisite for SSL connections to be successfully established is that the SSL certificate of the server be issued by one of the CAs in the truststore. The certificates of StartSSL are not present in the truststore of the Java runtime, atleast as of version 6, and therefore:
You could instruct your end users to perform the activity of importing the StartSSL CA certificate into the Java truststore. Links that may help include this StartSSL forum thread (only the first 4 steps are needed to import the CA certs into a truststore), a GitHub project, and this blog post; a disclaimer - I haven't attempted using any of those and you ought to be using it at your own risk.
Or, you could initialize your application with your own truststore using the -Djavax.net.ssl.trustStore=<path_to_truststore> -Djavax.net.ssl.trustStorePassword=<truststore_password> JVM startup flags, or execute the following code before initializing SSL connections:
System.setProperty("javax.net.ssl.trustStore","<path_to_truststore>");
System.setProperty("javax.net.ssl.trustStorePassword","<truststore_password>");
This is a viable approach only if your application is a Java SE application that does not happen to be an applet (or an application with similar restrictions on how the truststore is specified).
It would also help to read up the Java keytool documentation.
The following method loads the default (cacerts) keystore, checks to see if a certificate is installed, and installs it if not. It eliminates the need to manually run the keystore command on any servers.
It assumes that the default keystore password (changeit) is unchanged, update CACERTS_PASSWORD if not. Note that the method saves the keystore after adding a certificate, so after being run once the certificate will permanently be in the store.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
/**
* Add a certificate to the cacerts keystore if it's not already included
*/
public class SslUtil {
private static final String CACERTS_PATH = "/lib/security/cacerts";
// NOTE: DO NOT STORE PASSWORDS IN PLAIN TEXT CODE, LOAD AT RUNTIME FROM A SECURE CONFIG
// DEFAULT CACERTS PASSWORD IS PROVIDED HERE AS A QUICK, NOT-FOR-PRODUCTION WORKING EXAMPLE
// ALSO, CHANGE THE DEFAULT CACERTS PASSWORD, AS IT IMPLORES YOU TO!
private static final String CACERTS_PASSWORD = "changeit";
/**
* Add a certificate to the cacerts keystore if it's not already included
*
* #param alias The alias for the certificate, if added
* #param certInputStream The certificate input stream
* #throws KeyStoreException
* #throws NoSuchAlgorithmException
* #throws CertificateException
* #throws IOException
*/
public static void ensureSslCertIsInKeystore(String alias, InputStream certInputStream)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException{
//get default cacerts file
final File cacertsFile = new File(System.getProperty("java.home") + CACERTS_PATH);
if (!cacertsFile.exists()) {
throw new FileNotFoundException(cacertsFile.getAbsolutePath());
}
//load cacerts keystore
FileInputStream cacertsIs = new FileInputStream(cacertsFile);
final KeyStore cacerts = KeyStore.getInstance(KeyStore.getDefaultType());
cacerts.load(cacertsIs, CACERTS_PASSWORD.toCharArray());
cacertsIs.close();
//load certificate from input stream
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
final Certificate cert = cf.generateCertificate(certInputStream);
certInputStream.close();
//check if cacerts contains the certificate
if (cacerts.getCertificateAlias(cert) == null) {
//cacerts doesn't contain the certificate, add it
cacerts.setCertificateEntry(alias, cert);
//write the updated cacerts keystore
FileOutputStream cacertsOs = new FileOutputStream(cacertsFile);
cacerts.store(cacertsOs, CACERTS_PASSWORD.toCharArray());
cacertsOs.close();
}
}
}
Use it like so:
SslUtil.ensureSslCertIsInKeystore("startssl", new FileInputStream("/path/to/cert.crt"));
Apparently the mailgun engineers for some reason don't want to give us clear instructions on how to solve this. This is what I did
We run tomcat8 and connect via jersey web services to the mailgun API. I followed this users instructions and it worked fine. Hope this helps someone.
On 1/22, we updated our SSL certificates due to Symantec's PKI infrastructure set to become untrusted. Some older versions of Java do not have the "DigiCert Global Root G2" CA.
There are several options:
Import the "DigiCert Global Root G2" CA into your "cacerts" file.
Upgrade your JRE to 8u91 (or higher), which includes this root.
To import the "DigiCert Global Root G2" You can download the root from https://www.digicert.com/digicert-root-certificates.htm. Ensure you are downloading the correct root certificate.
Once the certificate is downloaded, you'll need to import it into with a command like the following:
keytool -import -trustcacerts -keystore /path/to/cacerts -storepass changeit -noprompt -alias digicert-global-root-g2 -file /path/to/digicert.crt
You will need to set the path to your Java Keystore and the location of the root certificate you downloaded.
So
1. /path/to/digicert.crt is the file you just downloaded.
2. /path/to/cacerts - This is in your JRE path. I "find / -name cacerts -print" this will help you quickly find all the java cacerts on your filesystem. For me it was /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/security/cacerts
Have a look at the following article: http://stilius.net/java/java_ssl.php
It contains code example which may help in case if you are trying to access your script from code.
Note that you either should use system properties
javax.net.ssl.keyStore
javax.net.ssl.keyStorePassword
to pass the SSL certificate to JVM or import it into JRE keystore by using keytool tool
I have found out that to ensure maxium security/validity I have to
import the SSL certificate
No you don't. You only need that step if your clients don't already trust the signer of the server certificate, which only arises if the server certificate is self-signed or signed e.g. by an internal CA.
That article contains the code for changing trust store's password and adding other certificates there:
thetechawesomeness.ideasmatter.info

Categories