In the windows personal certificate store, I am trying to programmatically install a certificate with the private key(using method setKeyEntry) using Java. But I get an exception when I do that.
Caused by: java.lang.UnsupportedOperationException: Cannot assign the key to the given alias.
at jdk.crypto.mscapi/sun.security.mscapi.CKeyStore.engineSetKeyEntry(CKeyStore.java:405)
at jdk.crypto.mscapi/sun.security.mscapi.CKeyStore$MY.engineSetKeyEntry(CKeyStore.java:57)
Code snippet:
KeyStore userCertStore = KeyStore.getInstance(getValue(CERTIFICATE_STORE_TYPE));
userCertStore.load(null,null);
for (iaik.x509.X509Certificate cert : user.getUserCertificates()) {
userCertStore.setCertificateEntry(cert.getSubjectDN().toString(), cert);
userCertStore.setKeyEntry(cert.getSubjectDN().toString(),user.getUserPrivateKey(cert),new
SecureStringBuffer(new StringBuffer(password)).toCharArray(),user.getUserCertificates());
}
The certificates are already set during setKeyEntry - do not store the certificate using setCertificateEntry.
setCertificateEntry is used to set trusted certificates (of the other party), the setKeyEntry is used to store private keys and the full certificate chain belonging to that private key.
So when you set the private key the alias is already taken by a "trusted certificate".
How to receive a x509 certificate from client? I'm using Java's Spring-Boot-Framework with embedded tomcat. For protyping I configured this with Java SE:
HttpsExchange httpsExchange = (HttpsExchange) httpReq;
name = httpsExchange.getSSLSession().getPeerPrincipal().getName();
A user gave me a reference to do this here (down below)
#RequestMapping(value = "/grab")
public void grabCert(HttpServletRequest servletRequest) {
Certificate[] certs =
(Certificate[]) servletRequest.getAttribute("javax.servlet.request.X509Certificate");
}
But I'm not able to get some certificate! Maybe because I'm using tomcat, and it is handling all SSL-Connections. So that no certificate is receiving my application. What I have to do, to get the clients certificate? The client certificate is used to get https connection. I need some information from the subject of the certificate. Thanks.
You have to get it from the HttpServletRequest.
You can check the answer to this question: How to get the certificate into the X509 filter (Spring Security)?:
No you can't get it that way. You need to grab it from the HttpServletRequest:
X509Certificate[] certs = (X509Certificate[])HttpServletRequest.getAttribute("javax.servlet.request.X509Certificate");
This was the post I was trying to point you to, written by Gandalf.
And this was the original question
I have a chain of certificates (X509Certificate []), but I have only one certificate in the chain. I need to get the complete chain.
I have tried the openssl command, but that is not useful here. Can someone please tell me how to:
Convert this X509Certificate to PEM or ASN.1/DER that I can save in my file storage?
Get the complete chain using this certificate?
Edit:
So, code-wise what I'm trying to achieve is something like:
protected static String convertToPem(X509Certificate cert) {
Base64 encoder = new Base64(64);
String cert_begin = "-----BEGIN CERTIFICATE-----\n";
String end_cert = "-----END CERTIFICATE-----";
byte[] derCert = cert.getEncoded();
String pemCertPre = new String(Base64.encodeBase64(derCert));
String pemCert = cert_begin + pemCertPre + end_cert;
return pemCert;
}
But, this is not working. Basically, I'm looking for a method that takes a X509Certificate object and then converts it to a .pem etc, that is saved on the device.
Convert this X509Certificate object to .cer/ .per/ .der that I can save in my file storage?
See, for example, the answer at OpenSSL's rsautl cannot load public key created with PEM_write_RSAPublicKey. It tells you how to convert keys to/from PEM and ASN.1/DER format, and includes a treatment of Traditional Format (a.k.a. SubjectPublicKeyInfo).
If you are not doing it programmatically, then you should search for the answer. There are plenty of off-topic question on how to use the openssl command to convert between ASN.1/DER and PEM. Or ask on Super User, where they specialize in commands and their use.
Get the complete chain using this certificate?
This is a well known problem in PKI called the Which Directory problem. The solution is to have the server or service provide the missing intermediate CA certificates. If you can't validate a web server or service's identity because you are missing intermediate CA certificates, then the server is misconfigured.
Once you have the intermediate CA certificates, you still have to root trust somewhere. You can use the self-signed CA, or one of the intermediates signed by the self-signed CA.
This answer is helpful in troubleshooting a misconfugred server using OpenSSL's s_client: SSL site and browser warning.
Related: if there was a global directory of certificates like the ITU envisioned in X.500, then you would not have the second problem. A relying party or user agent would just fetch the certificate it needed from the directory.
But we lack a central directory, so relying parties and user agents often use the CA Zoo (a.k.a., the local Trust Store or cacerts.pem). This has its own set of problems, like the wrong CA certifying a site or service.
One of the off-shoots is the CA Cartel, where browser are in partnership with the CAs at the CA/Browser Forum. Browser have requirements for inclusion, but they often can't punish a misbehaving CA like Trustwave.
And the browsers have managed to box themselves into a position where the Internet of Things (IoT) will not work because of the browser's reliance/requirements on server certificates signed by a CA.
Can somebody tell me how can i ignore the ssl certificate during web service call.
I am calling https weburl to get api response but getting peer not authenticated error.
Old examples are not working as some of methods are deprecated so can somebody tell me/ provide some sample code so that i will not get this error.
I just came to know that the problem is coming due to Certificate.
I am using 3rd party API for db calls & they have ssl certificate for their domain
i.e. www.dbprovider.com (SSL certificate is *.dbprovider.com)
& they created subdomain for us which look like myapp.dbprovider.com
So now the problem is no peer certificate is available when i try to hit through command
openssl s_client -ssl3 -showcerts -connect myapp.dbprovider.com:443
openssl s_client -tls1 -showcerts -connect myapp.dbprovider.com:443
Can somebody tell me what i should now do with it. Is there any control on dbprovider site so that they can provide me some configuration or i have to write code to ignore their certificate (but for ignoring certificate we are not getting their peer certificate)
Use a custom SSLSocketFactory as described here: http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e512. One such factory that ignores self-signed certs is EasySSLProtocolSocketFactory.
ProtocolSocketFactory factory = new EasySSLProtocolSocketFactory();
try {
URI uri = new URI(config.getBaseUrl());
int port = uri.getPort();
if (port == -1) {
port = 443;
}
Protocol easyHttps = new Protocol(uri.getScheme(), factory, port);
hostConfiguration.setHost(uri.getHost(), port, easyHttps);
} catch (URISyntaxException e) {
throw new IOException("could not parse URI " + config.getBaseUrl(), e);
}
Source: http://frightanic.com/software-development/self-signed-certificates-in-apache-httpclient/
I am calling some HTTPS web service which the following Client:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
/**
* Handles http and https connections. It sends XML request over http (or https)
* to SOAP web service and receive the XML reply.
*
* #author mhewedy
* #date 30.10.2010
*/
public class HttpWSXmlClient
{
private final String ws_url;
private byte[] requestData;
public HttpWSXmlClient(String wsUrl)
{
this.ws_url = wsUrl;
}
public void readRequest(String xmlRequestFilePath)
{
try
{
InputStream istream = new FileInputStream(xmlRequestFilePath);
byte[] data = stream2Bytes(istream);
istream.close();
this.requestData = data;
} catch (Exception e)
{
throw new RuntimeException(e.getMessage());
}
}
/**
*
* #param ps
* PrintStream object to send the debugging info to.
* #return
* #throws IOException
*/
public byte[] sendAndRecieve(PrintStream ps) throws IOException
{
if (requestData == null)
throw new RuntimeException(
"the request data didn't initialized yet.");
if (ps != null)
ps.println("Request:\n" + new String(requestData));
URL url = new URL(ws_url);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
// or HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("content-type", "text/xml");
connection.connect();
OutputStream os = connection.getOutputStream();
os.write(requestData);
InputStream is = connection.getInputStream();
byte[] rply = stream2Bytes(is);
if (ps != null)
ps.println("Response:\n" + new String(rply));
os.close();
is.close();
connection.disconnect();
return rply;
}
public byte[] sendAndRecieve() throws IOException
{
return sendAndRecieve(null);
}
private byte[] stream2Bytes(InputStream istream) throws IOException
{
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
int c;
while ((c = istream.read()) != -1)
{
if (c != 0x0A && c != 0x0D) // prevent new line character from being
// written
{
if (c == 0x09)
c = 0x20; // prevent tab character from being written,
// instead write single space char
outstream.write(c);
}
}
byte[] ret = outstream.toByteArray();
outstream.close();
return ret;
}
}
Test:
public class Test
{
private static final String WS_URL = "https://some_server/path/to/ws";
public static void main(String[] args) throws Exception
{
HttpWSXmlClient client = new HttpWSXmlClient(WS_URL);
client.readRequest("request.xml");
client.sendAndRecieve(System.out);
}
}
I got the following output:
Exception in thread "Main Thread" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1591)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:187)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:181)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1035)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:124)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:516)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:454)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1096)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1107)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:415)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at com.se.swstest.HttpWSXmlClient.sendAndRecieve(HttpWSXmlClient.java:63)
at com.se.swstest.Test.main(Test.java:11)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:285)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:191)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1014)
... 12 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:280)
... 18 more
Do I need any certificate to be put at jdk/jre/lib/security???
Also, I have a xxx_IE.crt and xxx_FX.crt (for Firefox and IE respectively, and they don't work for the above Java client, so do I need a specific certificate for the Java client?
Thanks.
You need to set certificate to hit this url. use below code to set keystore:
System.setProperty("javax.net.ssl.trustStore","clientTrustStore.key");
System.setProperty("javax.net.ssl.trustStorePassword","qwerty");
Java 8 Solution: I just had this problem and solved it by adding the remote site's certificate to my Java keystore. My solution was based on the solution at the myshittycode blog, which was based on a previous solution in mykong's blog. These blog article solutions boil down to downloading a program called InstallCert, which is a Java class you can run from the command line to obtain the certificate. You then proceed to install the certificate in Java's keystore.
The InstallCert Readme worked perfectly for me. You just need to run the following commands:
javac InstallCert.java
java InstallCert [host]:[port] (Enter the given list number of the certificate you want to add in the list when you run the command - likely just 1)
keytool -exportcert -alias [host]-1 -keystore jssecacerts -storepass changeit -file [host].cer
sudo keytool -importcert -alias [host] -keystore [path to system keystore] -storepass changeit -file [host].cer
See the referenced README file for an example if need be.
If you do not need the SSL security then you might want to switch it off.
/**
* disable SSL
*/
private void disableSslVerification() {
try {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
} };
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
I've run into this a few times and it was due to a certificate chain being incomplete. If you are using the standard java trust store, it may not have a certificate that is needed to complete the certificate chain which is required to validate the certificate of the SSL site you are connecting to.
I ran into this problem with some DigiCert certificates and had to manually add the intermediary cert myself.
Here is the solution that I used for installing a site's public cert into the systems keystore for use.
Download the certificate with the following command:
unix, linux, mac
openssl s_client -connect [host]:[port|443] < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > [host].crt
windows
openssl s_client -connect [host]:[port|443] < NUL | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > [host].crt
That will create a crt that can be used to import into a keystore.
Install the new certificate with the command:
keytool -import -alias "[host]" -keystore [path to keystore] -file [host].crt
This will allow you to import the new cert from the site that is causing the exception.
I had hit this when I was trying to initiate a SOAP request from Java code. What worked for me was:
Get the Server certificate by hitting the URL in browser: http://docs.bvstools.com/home/ssl-documentation/exporting-certificate-authorities-cas-from-a-website
This link has all the steps to get the server certificate
Once you have the server certificate with you follow http://java.globinch.com/enterprise-java/security/pkix-path-building-failed-validation-sun-security-validatorexception/#Valid-Certification-Path-to-Requested-Target .
Copying the text from the link, in case this link dies:
All you need to do to fix this error is to add the server certificate
to your trusted Java key store. First You need to download the
document from the server.
Once you have the certificate in your hard drive you can import it to
the Java trust store. To import the certificate to the trusted Java
key store, you can use the java ‘keytool‘ tool. On command prompt
navigate to JRE bin folder, in my case the path is : C:\Program
Files\Java\jdk1.7.0_75\jre\bin . Then use keytool command as follows
to import the certificate to JRE.
keytool -import -alias _alias_name_ -keystore ..\lib\security\cacerts
-file _path_to_cer_file
It will ask for a password. By default the password is “changeit”. If
the password is different you may not be able to import the
certificate.
This error can also happen if the server only sends its leaf certificate and does not send all the chain certificates needed to build the trust chain to the root CA. Unfortunately this is a common misconfiguration of servers.
Most browsers work around this problem if they already know the missing chain certificate from earlier visits or maybe download the missing certificate if the leaf certificate contains a URL for CA issuers in Authority Information Access (AIA). But this behavior is usually restricted to desktop browsers and other tools simply fail because they cannot build the trust chain.
You can make the JRE to automatically download the intermediate certificate by setting com.sun.security.enableAIAcaIssuers to true
To verify if the server is sending all the chain certificates you can enter the host in the following SSL certificate validation tool https://www.digicert.com/help/
On Mac OS I had to open the server's self-signed certificate with system Keychain Access tool, import it, dobubleclick it and then select "Always trust" (even though I set the same in importer).
Before that, of course I ran java key took with -importcert to import same file to cacert storage.
Thank to #danny-paul answer (https://stackoverflow.com/a/60851862/9239136), i resolved my problem on self-hosted instance.
I use Birt application with Tomcat on Windows Server and it was not able to download pictures from Apache service.
I noticed my Apache configuration was incomplete on Windows Server.
The third line was commented out. I uncommented it, restart Apache and it works.
SSLEngine on
SSLCertificateFile "c:/Apache24/conf/ssl/cert.pem"
SSLCertificateKeyFile "c:/Apache24/conf/ssl/privkey.pem"
SSLCACertificateFile "c:/Apache24/conf/ssl/chain.pem"
For me, I had encountered this error when invoking a webservice call, make sure that the site has a valid ssl, i.e the logo on the side of the url is checked, otherwise need to add the certificate to trusted key store in your machine
I also faced this type of issue.I am using tomcat server then i put endorsed folder in tomcat then its start working.And also i replaced JDK1.6 with 1.7 then also its working.Finally i learn SSL then I resolved this type of issues.First you need to download the certificates from that servie provider server.then you are handshake is successfull.
1.Try to put endorsed folder in your server
Next way
2.use jdk1.7
Next
3.Try to download valid certificates using SSL