ChatGPT解决这个技术问题 Extra ChatGPT

How to import a .cer certificate into a java keystore?

During the development of a Java webservice client I ran into a problem. Authentication for the webservice is using a client certificate, a username and a password. The client certificate I received from the company behind the webservice is in .cer format. When I inspect the file using a text editor, it has the following contents:

-----BEGIN CERTIFICATE-----
[Some base64 encoded data]
-----END CERTIFICATE-----

I can import this file as a certificate in Internet Explorer (without having to enter a password!) and use it to authenticate with the webservice.

I was able to import this certificate into a keystore by first stripping the first and last line, converting to unix newlines and running a base64-decode. The resulting file can be imported into a keystore (using the keytool command). When I list the entries in the keystore, this entry is of the type trustedCertEntry. Because of this entry type (?) I cannot use this certificate to authenticate with the webservice. I'm beginning to think that the provided certificate is a public certificate which is being used for authentication...

A workaround I have found is to import the certificate in IE and export it as a .pfx file. This file can be loaded as a keystore and can be used to authenticate with the webservice. However I cannot expect my clients to perform these steps every time they receive a new certificate. So I would like to load the .cer file directly into Java. Any thoughts?

Additional info: the company behind the webservice told me that the certificate should be requested (using IE & the website) from the PC and user that would import the certificate later.


L
Lior Bar-On

If you want to authenticate you need the private key - there is no other option.

A certificate is a public key with extra properties (like company name, country,...) that is signed by some Certificate authority that guarantees that the attached properties are true.

.CER files are certificates and don't have the private key. The private key is provided with a .PFX keystore file normally. If you really authenticate is because you already had imported the private key.

You normally can import .CER certificates without any problems with keytool -importcert -file certificate.cer -keystore keystore.jks -alias "Alias"


Turns out the private key is being generated by a plugin for IE. Only solution for now is to import the certificate in IE and export a .pfx file.
.CER files do have the public key. They don't have the private key. Suggest editing..
What does -alias do here ?
:( --> keytool error: java.lang.Exception: Input not an X.509 certificate
@hop A java keystore can have multiple certificates each one with a different alias to identify it. You can use it as reference to identify it and/or to retrieve it programatically by alias name.
4
4 revs, 2 users 91%

Importing .cer certificate file downloaded from browser (open the url and dig for details) into cacerts keystore in java_home\jre\lib\security worked for me, as opposed to attemps to generate and use my own keystore.

Go to your java_home\jre\lib\security (Windows) Open admin command line there using cmd and CTRL+SHIFT+ENTER Run keytool to import certificate: (Replace yourAliasName and path\to\certificate.cer respectively)

 ..\..\bin\keytool -import -trustcacerts -keystore cacerts -storepass changeit -noprompt -alias yourAliasName -file path\to\certificate.cer

This way you don't have to specify any additional JVM options and the certificate should be recognized by the JRE.


path\to\cert. If my file is on the desktop how can I path it? C:/user/desktop/ or ../../../../desktop/filename
on MacOS /Linux this command works with sudo. Thanks. but what is noprompt param ? I didn't use it and still succeeded.
Note that when using the JDK for developing, the correct path is java_home\jdk_x.xx\jre\lib\security For an absolute path use backslash, e.g. "C:\myCert.crt" Quotation marks are optional if the path does not contain whitespaces.
Thanks a million times.
Question: What about the private key? The discussion is about client certificates. My understanding is that one needs create a CSR with a private key, then receive a client certificate from the remote website company and then match the client certificate to the private key. Your answer does not seem to mention anything about the private key. Just asking.
P
Patrick M

Here is the code I've been using for programatically importing .cer files into a new KeyStore.

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
//VERY IMPORTANT.  SOME OF THESE EXIST IN MORE THAN ONE PACKAGE!
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

//Put everything after here in your function.
KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);//Make an empty store
InputStream fis = /* insert your file path here */;
BufferedInputStream bis = new BufferedInputStream(fis);

CertificateFactory cf = CertificateFactory.getInstance("X.509");

while (bis.available() > 0) {
    Certificate cert = cf.generateCertificate(bis);
    trustStore.setCertificateEntry("fiddler"+bis.available(), cert);
}

d
dogbane

You shouldn't have to make any changes to the certificate. Are you sure you are running the right import command?

The following works for me:

keytool -import -alias joe -file mycert.cer -keystore mycerts -storepass changeit

where mycert.cer contains:

-----BEGIN CERTIFICATE-----
MIIFUTCCBDmgAwIBAgIHK4FgDiVqczANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY
...
RLJKd+SjxhLMD2pznKxC/Ztkkcoxaw9u0zVPOPrUtsE/X68Vmv6AEHJ+lWnUaWlf
zLpfMEvelFPYH4NT9mV5wuQ1Pgurf/ydBhPizc0uOCvd6UddJS5rPfVWnuFkgQOk
WmD+yvuojwsL38LPbtrC8SZgPKT3grnLwKu18nm3UN2isuciKPF2spNEFnmCUWDc
MMicbud3twMSO6Zbm3lx6CToNFzP
-----END CERTIFICATE-----

When I try to import the unmodified certificate into the keystore, I get the error "keytool error: java.lang.Exception: Input not an X.509 certificate". After modifying the certificate in the way I described in my post, I am able to import the certificate without errors with a command similar to yours. However it is imported as a trustedCertEntry and is not used when accessing the webservice.
Can you please add the command the exception to the question? Are you sure you are specifying an alias in your import command?
Don't forget to run cmd as admin if you are using Windows
A
Adam Michalik

An open source GUI tool is available at keystore-explorer.org

KeyStore Explorer KeyStore Explorer is an open source GUI replacement for the Java command-line utilities keytool and jarsigner. KeyStore Explorer presents their functionality, and more, via an intuitive graphical user interface.

Following screens will help (they are from the official site)

Default screen that you get by running the command:

shantha@shantha:~$./Downloads/kse-521/kse.sh

https://i.stack.imgur.com/De08D.png

And go to Examine and Examine a URL option and then give the web URL that you want to import.

https://i.stack.imgur.com/rgoI0.png

This is one of Use case and rest is up-to the user(all credits go to the keystore-explorer.org)


ironically, the provided link leads to a not certified http - no s - site.
@MartinMeeser, the site is their official one and my recommendation is not to share any sensitive or personal information when you refer it.
C
Chochos

The certificate that you already have is probably the server's certificate, or the certificate used to sign the server's certificate. You will need it so that your web service client can authenticate the server.

But if additionally you need to perform client authentication with SSL, then you need to get your own certificate, to authenticate your web service client. For this you need to create a certificate request; the process involves creating your own private key, and the corresponding public key, and attaching that public key along with some of your info (email, name, domain name, etc) to a file that's called the certificate request. Then you send that certificate request to the company that's already asked you for it, and they will create your certificate, by signing your public key with their private key, and they'll send you back an X509 file with your certificate, which you can now add to your keystore, and you'll be ready to connect to a web service using SSL requiring client authentication.

To generate your certificate request, use "keytool -certreq -alias -file -keypass -keystore ". Send the resulting file to the company that's going to sign it.

When you get back your certificate, run "keytool -importcert -alias -keypass -keystore ".

You may need to used -storepass in both cases if the keystore is protected (which is a good idea).


B
Brad Parks

Here's a script I used to batch import a bunch of crt files in the current directory into the java keystore. Just save this to the same folder as your certificate, and run it like so:

./import_all_certs.sh

import_all_certs.sh

KEYSTORE="$(/usr/libexec/java_home)/jre/lib/security/cacerts";

function running_as_root()
{
  if [ "$EUID" -ne 0 ]
    then echo "NO"
    exit
  fi

  echo "YES"
}

function import_certs_to_java_keystore
{
  for crt in *.crt; do 
    echo prepping $crt 
    keytool -import -file $crt -storepass changeit -noprompt --alias alias__${crt} -keystore $KEYSTORE
    echo 
  done
}

if [ "$(running_as_root)" == "YES" ]
then
  import_certs_to_java_keystore
else
  echo "This script needs to be run as root!"
fi

c
code4kix

Here's how this worked for me:

Save as .txt the certificate data in the following format in a text editor -----BEGIN CERTIFICATE----- [data serialized by microsoft] -----END CERTIFICATE----- Open chrome browser (this step might work with other browsers too) settings > show advanced settings > HTTPS/SSL > manage certificates Import the .txt in step 1 Select and export that certificate in Base-64 encoded format. Save it as .cer Now you can use keytool or Portecle to import it to your java keystore


H
Hakan54

Although a-lot of good answers have been provided I want to give an alternative for loading the ssl material programatically. You can try out the following snippet:

Path certificatePath = Paths.get("/path/to/certificate.cer");
List<Certificate> certificates = CertificateUtils.loadCertificate(certificatePath);

SSLFactory sslFactory = SSLFactory.builder()
        .withTrustMaterial(certificates)
        .build();

SSLContext sslContext = sslFactory.getSslContext();

It can handle pem, der (binary) and p7b formatted files. This example code snippet is from the library: GitHub - SSLContext Kickstart You can add it with the following snippet:

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>sslcontext-kickstart</artifactId>
    <version>7.0.2</version>
</dependency>