Import PEM into Java Key Store - java

I am trying to connect to an SSL server which requires me to authenticate myself. In order to use SSL over Apache MINA I need a suitable JKS file. However, I have only been given a .PEM file.
How would I go about creating a JKS file from a PEM file?

First, convert your certificate in a DER format :
openssl x509 -outform der -in certificate.pem -out certificate.der
And after, import it in the keystore :
keytool -import -alias your-alias -keystore cacerts -file certificate.der

If you only want to import a certificate in PEM format into a keystore, keytool will do the job:
keytool -import -alias *alias* -keystore cacerts -file *cert.pem*

If you need an easy way to load PEM files in Java without having to deal with external tools (opensll, keytool), here is my code I use in production :
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import javax.xml.bind.DatatypeConverter;
public class PEMImporter {
public static SSLServerSocketFactory createSSLFactory(File privateKeyPem, File certificatePem, String password) throws Exception {
final SSLContext context = SSLContext.getInstance("TLS");
final KeyStore keystore = createKeyStore(privateKeyPem, certificatePem, password);
final KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, password.toCharArray());
final KeyManager[] km = kmf.getKeyManagers();
context.init(km, null, null);
return context.getServerSocketFactory();
}
/**
* Create a KeyStore from standard PEM files
*
* #param privateKeyPem the private key PEM file
* #param certificatePem the certificate(s) PEM file
* #param the password to set to protect the private key
*/
public static KeyStore createKeyStore(File privateKeyPem, File certificatePem, final String password)
throws Exception, KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
final X509Certificate[] cert = createCertificates(certificatePem);
final KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null);
// Import private key
final PrivateKey key = createPrivateKey(privateKeyPem);
keystore.setKeyEntry(privateKeyPem.getName(), key, password.toCharArray(), cert);
return keystore;
}
private static PrivateKey createPrivateKey(File privateKeyPem) throws Exception {
final BufferedReader r = new BufferedReader(new FileReader(privateKeyPem));
String s = r.readLine();
if (s == null || !s.contains("BEGIN PRIVATE KEY")) {
r.close();
throw new IllegalArgumentException("No PRIVATE KEY found");
}
final StringBuilder b = new StringBuilder();
s = "";
while (s != null) {
if (s.contains("END PRIVATE KEY")) {
break;
}
b.append(s);
s = r.readLine();
}
r.close();
final String hexString = b.toString();
final byte[] bytes = DatatypeConverter.parseBase64Binary(hexString);
return generatePrivateKeyFromDER(bytes);
}
private static X509Certificate[] createCertificates(File certificatePem) throws Exception {
final List<X509Certificate> result = new ArrayList<X509Certificate>();
final BufferedReader r = new BufferedReader(new FileReader(certificatePem));
String s = r.readLine();
if (s == null || !s.contains("BEGIN CERTIFICATE")) {
r.close();
throw new IllegalArgumentException("No CERTIFICATE found");
}
StringBuilder b = new StringBuilder();
while (s != null) {
if (s.contains("END CERTIFICATE")) {
String hexString = b.toString();
final byte[] bytes = DatatypeConverter.parseBase64Binary(hexString);
X509Certificate cert = generateCertificateFromDER(bytes);
result.add(cert);
b = new StringBuilder();
} else {
if (!s.startsWith("----")) {
b.append(s);
}
}
s = r.readLine();
}
r.close();
return result.toArray(new X509Certificate[result.size()]);
}
private static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
final PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
final KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) factory.generatePrivate(spec);
}
private static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException {
final CertificateFactory factory = CertificateFactory.getInstance("X.509");
return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
}
}
Have fun.

I've developed http://code.google.com/p/java-keyutil/ which imports PEM certificates straight into a Java keystore. Its primary purpose is to import a multi-part PEM Operating System certificate bundles such as ca-bundle.crt. These often includes headers which keytool cannot handle
</self promotion>

In my case I had a pem file which contained two certificates and an encrypted private key to be used in mutual SSL authentication.
So my pem file looked like this:
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,C8BF220FC76AA5F9
...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
Here is what I did
Split the file into three separate files, so that each one contains just one entry,
starting with ---BEGIN.. and ending with ---END.. lines. Lets assume we now have three files: cert1.pem, cert2.pem, and pkey.pem.
Convert pkey.pem into DER format using openssl and the following syntax:
openssl pkcs8 -topk8 -nocrypt -in pkey.pem -inform PEM -out pkey.der -outform DER
Note, that if the private key is encrypted you need to supply a password( obtain it from the supplier of the original pem file ) to convert to DER format,
openssl will ask you for the password like this: "enter a passphrase for pkey.pem: ".
If conversion is successful, you will get a new file called pkey.der.
Create a new java keystore and import the private key and the certificates:
String keypass = "password"; // this is a new password, you need to come up with to protect your java key store file
String defaultalias = "importkey";
KeyStore ks = KeyStore.getInstance("JKS", "SUN");
// this section does not make much sense to me,
// but I will leave it intact as this is how it was in the original example I found on internet:
ks.load( null, keypass.toCharArray());
ks.store( new FileOutputStream ( "mykeystore" ), keypass.toCharArray());
ks.load( new FileInputStream ( "mykeystore" ), keypass.toCharArray());
// end of section..
// read the key file from disk and create a PrivateKey
FileInputStream fis = new FileInputStream("pkey.der");
DataInputStream dis = new DataInputStream(fis);
byte[] bytes = new byte[dis.available()];
dis.readFully(bytes);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
byte[] key = new byte[bais.available()];
KeyFactory kf = KeyFactory.getInstance("RSA");
bais.read(key, 0, bais.available());
bais.close();
PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
PrivateKey ff = kf.generatePrivate (keysp);
// read the certificates from the files and load them into the key store:
Collection col_crt1 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert1.pem"));
Collection col_crt2 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert2.pem"));
Certificate crt1 = (Certificate) col_crt1.iterator().next();
Certificate crt2 = (Certificate) col_crt2.iterator().next();
Certificate[] chain = new Certificate[] { crt1, crt2 };
String alias1 = ((X509Certificate) crt1).getSubjectX500Principal().getName();
String alias2 = ((X509Certificate) crt2).getSubjectX500Principal().getName();
ks.setCertificateEntry(alias1, crt1);
ks.setCertificateEntry(alias2, crt2);
// store the private key
ks.setKeyEntry(defaultalias, ff, keypass.toCharArray(), chain );
// save the key store to a file
ks.store(new FileOutputStream ( "mykeystore" ),keypass.toCharArray());
(optional) Verify the content of your new key store:
$ keytool -list -keystore mykeystore -storepass password
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 3 entries:
cn=...,ou=...,o=.., Sep 2, 2014, trustedCertEntry,
Certificate fingerprint (SHA1): 2C:B8: ...
importkey, Sep 2, 2014, PrivateKeyEntry,
Certificate fingerprint (SHA1): 9C:B0: ...
cn=...,o=...., Sep 2, 2014, trustedCertEntry,
Certificate fingerprint (SHA1): 83:63: ...
(optional) Test your certificates and private key from your new key store against your SSL server:
( You may want to enable debugging as an VM option: -Djavax.net.debug=all )
char[] passw = "password".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS", "SUN");
ks.load(new FileInputStream ( "mykeystore" ), passw );
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passw);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
TrustManager[] tm = tmf.getTrustManagers();
SSLContext sclx = SSLContext.getInstance("TLS");
sclx.init( kmf.getKeyManagers(), tm, null);
SSLSocketFactory factory = sclx.getSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket( "192.168.1.111", 443 );
socket.startHandshake();
//if no exceptions are thrown in the startHandshake method, then everything is fine..
Finally register your certificates with HttpsURLConnection if plan to use it:
char[] passw = "password".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS", "SUN");
ks.load(new FileInputStream ( "mykeystore" ), passw );
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passw);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
TrustManager[] tm = tmf.getTrustManagers();
SSLContext sclx = SSLContext.getInstance("TLS");
sclx.init( kmf.getKeyManagers(), tm, null);
HostnameVerifier hv = new HostnameVerifier()
{
public boolean verify(String urlHostName, SSLSession session)
{
if (!urlHostName.equalsIgnoreCase(session.getPeerHost()))
{
System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
}
return true;
}
};
HttpsURLConnection.setDefaultSSLSocketFactory( sclx.getSocketFactory() );
HttpsURLConnection.setDefaultHostnameVerifier(hv);

I used Keystore Explorer
Open JKS with a private key
Examine signed PEM from CA
Import key
Save JKS

I'm always forgetting how to do this because it's something that I just do once in a while, this is one possible solution, and it just works:
Go to your favourite browser and download the main certificate from the secured website.
Execute the two following lines of code:
$ openssl x509 -outform der -in GlobalSignRootCA.crt -out GlobalSignRootCA.der
$ keytool -import -alias GlobalSignRootCA -keystore GlobalSignRootCA.jks -file GlobalSignRootCA.der
If executing in Java SE environment add the following options:
$ java -Djavax.net.ssl.trustStore=GlobalSignRootCA.jks -Djavax.net.ssl.trustStorePassword=trustStorePassword -jar MyJar.jar
Or add the following to the java code:
System.setProperty("javax.net.ssl.trustStore", "GlobalSignRootCA.jks");
System.setProperty("javax.net.ssl.trustStorePassword","trustStorePassword");
The other option for step 2 is to just using the keytool command. Bellow is an example with a chain of certificates:
$ keytool -import -file org.eu.crt -alias orgcrt -keystore globalsignrs.jks
$ keytool -import -file GlobalSignOrganizationValidationCA-SHA256-G2.crt -alias globalsignorgvalca -keystore globalsignrs.jks
$ keytool -import -file GlobalSignRootCA.crt -alias globalsignrootca -keystore globalsignrs.jks

There is also a GUI tool that allows visual JKS creation and certificates importing.
http://portecle.sourceforge.net/
Portecle is a user friendly GUI application for creating, managing and examining keystores, keys, certificates, certificate requests, certificate revocation lists and more.

I got it from internet. It works pretty good for pem files that contains multiple entries.
#!/bin/bash
pemToJks()
{
# number of certs in the PEM file
pemCerts=$1
certPass=$2
newCert=$(basename "$pemCerts")
newCert="${newCert%%.*}"
newCert="${newCert}"".JKS"
##echo $newCert $pemCerts $certPass
CERTS=$(grep 'END CERTIFICATE' $pemCerts| wc -l)
echo $CERTS
# For every cert in the PEM file, extract it and import into the JKS keystore
# awk command: step 1, if line is in the desired cert, print the line
# step 2, increment counter when last line of cert is found
for N in $(seq 0 $(($CERTS - 1))); do
ALIAS="${pemCerts%.*}-$N"
cat $pemCerts |
awk "n==$N { print }; /END CERTIFICATE/ { n++ }" |
$KEYTOOLCMD -noprompt -import -trustcacerts \
-alias $ALIAS -keystore $newCert -storepass $certPass
done
}
pemToJks <pem to import> <pass for new jks>

Although this question is pretty old and it has already a-lot answers, I think it is worth to provide an alternative. Using native java classes makes it very verbose to just use pem files and almost forces you wanting to convert the pem files into p12 or jks files as using p12 or jks files are much easier. I want to give anyone who wants an alternative for the already provided answers.
GitHub - SSLContext Kickstart
var keyManager = PemUtils.loadIdentityMaterial("certificate-chain.pem", "private-key.pem");
var trustManager = PemUtils.loadTrustMaterial("some-trusted-certificate.pem");
var sslFactory = SSLFactory.builder()
.withIdentityMaterial(keyManager)
.withTrustMaterial(trustManager)
.build();
var sslContext = sslFactory.getSslContext();
I need to provide some disclaimer here, I am the library maintainer

OpenJDK keytool handles PEM certificates natively now (and has been for a few releases but I'm not sure since when).
keytool recommends against specifying the cacerts file path like any other keystore but using -cacerts option instead.
So the command line which works with OpenJDK 18 (and probably many earlier versions) is:
keytool -cacerts -import -alias <alias> -file <path_to_cert.pem>

If you want to do this on Android, there are a few minor tweaks that can be added to the PEMImporter class from this great answer. To summarize those:
First I used Android Studio to translate into Kotlin (this is not necessary, I just prefer it). The original class contained all static methods, so this resulted in a named object instead.
javax.xml.bind.DatatypeConverter was removed from the java core in version 11. Although you can still import it (in gradle:
implementation("javax.xml.bind:jaxb-api:2.4.0-b180830.0359"), this does not work on Android and it is simpler to use java.util.Base64 for the tasks it performed (namely, translating base64 to bytes). The output is identical (although you need to trim line endings in the raw PEM data).
Replace SunX509 and JKS with PKIX. It is only necessary in the first case, and in the second case probably inconsequential; I do not think it has any significance if you are populating a KeyStore with already initialized PrivateKey etc. objects as is done here. I in fact used getDefaultAlgorithm() in place of "JKS" in createKeyStore, and although that default is currently "jks", the key store worked fine in a KeyManagerFactory created with PKIX as the algorithm.
I should also note that I am not using the createSSLFactory method and am instead using the output of createKeyStore() to initialize a KeyManagerFactory and extract KeyManagers used to initialize anSSLContext:
val context = SSLContext.getInstance(contextProtocol)
val password = String(...)
val ks : KeyStore = try {
PEMImporter.createKeyStore(
File(keyPath),
File(certPath),
password
)
} catch (ex : Throwable) { ... }
val kmf = KeyManagerFactory.getInstance("PKIX")
try { kmf.init(ks, password.toCharArray()) }
It probably doesn't matter much what the password is here since the PEMImporter works with already unencrypted key data -- unless you want to write a PrivateKey back to a file (I presume getEncoded() is a step in that direction but I've never had need to do this). It just has to match in the two uses above.
I also added a catch for RSA PRIVATE KEYS, which, as it turns out, are
not the same as PEM keys with no "RSA" in the first line; a subtlety I was previously unaware of. The former are PKCS #1, the latter PKCS #8; you should be able to use whatever tool you normally use to deal with these (eg., when creating keys with certtool, use --pkcs8). Note that doesn't mean PKCS #8 keys aren't potentially RSA based, it's just about the protocol used to store and extract the key data.
Here's my Android version of PEMImporter in Kotlin:
import java.io.*
import java.security.*
import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.security.interfaces.RSAPrivateKey
import java.security.spec.InvalidKeySpecException
import java.security.spec.PKCS8EncodedKeySpec
import java.util.*
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLServerSocketFactory
object PEMImporter {
#Throws(Exception::class)
fun createSSLFactory(
privateKeyPem: File,
certificatePem: File?,
password: String
): SSLServerSocketFactory {
val context = SSLContext.getInstance("TLS")
val keystore = createKeyStore(privateKeyPem, certificatePem, password)
val kmf = KeyManagerFactory.getInstance("PKIX")
kmf.init(keystore, password.toCharArray())
val km = kmf.keyManagers
context.init(km, null, null)
return context.serverSocketFactory
}
/**
* Create a KeyStore from standard PEM files
*
* #param privateKeyPem the private key PEM file
* #param certificatePem the certificate(s) PEM file
* #param password the password to set to protect the private key
*/
#Throws(
Exception::class,
KeyStoreException::class,
IOException::class,
NoSuchAlgorithmException::class,
CertificateException::class
)
fun createKeyStore(privateKeyPem: File, certificatePem: File?, password: String): KeyStore {
val cert = createCertificates(certificatePem)
val keystore = KeyStore.getInstance(KeyStore.getDefaultType())
keystore.load(null)
// Import private key
val key = createPrivateKey(privateKeyPem)
keystore.setKeyEntry(privateKeyPem.name, key, password.toCharArray(), cert)
return keystore
}
#Throws(Exception::class)
private fun createPrivateKey(privateKeyPem: File): PrivateKey {
val r = BufferedReader(FileReader(privateKeyPem))
var s = r.readLine()
if (s.contains("BEGIN RSA PRIVATE KEY")) {
r.close()
throw IllegalArgumentException(privateKeyPem.name +
" is a PKCS #1 key, not a PKCS #8.")
}
if (s == null || (!s.contains("BEGIN PRIVATE KEY"))) {
r.close()
throw IllegalArgumentException("Bad private key header (${privateKeyPem.name}): $s")
}
val b = StringBuilder()
s = ""
while (s != null) {
if (s.contains("END PRIVATE KEY")) {
break
}
b.append(s.trimEnd())
s = r.readLine()
}
r.close()
val hexString = b.toString()
// Base64 is in java.util.
val bytes = Base64.getDecoder().decode(hexString)
return generatePrivateKeyFromDER(bytes)
}
#Throws(Exception::class)
private fun createCertificates(certificatePem: File?): Array<X509Certificate> {
val result = mutableListOf<X509Certificate>()
val r = BufferedReader(FileReader(certificatePem))
var s = r.readLine()
if (s == null || !s.contains("BEGIN CERTIFICATE")) {
r.close()
throw IllegalArgumentException("No CERTIFICATE found")
}
var b = StringBuilder()
while (s != null) {
if (s.contains("END CERTIFICATE")) {
val hexString = b.toString()
val bytes = Base64.getDecoder().decode(hexString.trimEnd())
val cert = generateCertificateFromDER(bytes)
result.add(cert)
b = StringBuilder()
} else {
if (!s.startsWith("----")) {
b.append(s)
}
}
s = r.readLine()
}
r.close()
return result.toTypedArray()
}
#Throws(InvalidKeySpecException::class, NoSuchAlgorithmException::class)
private fun generatePrivateKeyFromDER(keyBytes: ByteArray): RSAPrivateKey {
val spec = PKCS8EncodedKeySpec(keyBytes)
val factory = KeyFactory.getInstance("RSA")
return factory.generatePrivate(spec) as RSAPrivateKey
}
#Throws(CertificateException::class)
private fun generateCertificateFromDER(certBytes: ByteArray): X509Certificate {
val factory = CertificateFactory.getInstance("X.509")
return factory.generateCertificate(ByteArrayInputStream(certBytes)) as X509Certificate
}
}

Related

Import elliptic curve Certificate and Private Key into Java Keystore using java.security.KeyStore

I'm currently working on a project that involves getting an Elliptic Curve Certificate / Private Key package in either PEM or DER format from Vault and needing to import it into a Java Keystore. I can find plenty of information on doing this with keytool, but am unable to find information about how to successfully convert a DER encoded string into a PrivateKeyEntry to insert it into the keystore.
Below is my non-working code. certificate , key, and issuingCa are all PEM or DER encoded Strings (I can specify which format I want to get back from the issuer and pass whichever I can get to work)
private KeyStore packKeystore(String certificate, String key, String issuingCa, String name) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
// Create the keystore
KeyStore retVal = KeyStore.getInstance(KeyStore.getDefaultType());
retVal.load(null, sslKeystorePassword.toCharArray());
var cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
var cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certificate.getBytes()));
retVal.setCertificateEntry(name, cert);
Certificate issuer = null;
if (issuingCa != null) {
issuer = cf.generateCertificate(new ByteArrayInputStream(issuingCa.getBytes(StandardCharsets.UTF_8)));
}
if (key != null) {
var certs = new HashSet<Certificate>();
certs.add(issuer);
certs.add(cert);
PrivateKeyEntry pk = /// How do I create this from what I have????
retVal.setKeyEntry( pk, certs.toArray());
}
return retVal;
}
After some experimentation and research I've learned that the PrivateKey class doesn't like the "old" PEM format where the private key looks like ---- BEGIN EC PRIVATE KEY-----.
I was eventually able to parse a PrivateKey object from a keypair like this:
var parsedKey = new org.bouncycastle.openssl.PEMParser(new StringReader(key)).readObject();
var pair = new org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter().getKeyPair((org.bouncycastle.openssl.PEMKeyPair) parsedKey);
retVal.setKeyEntry(name, pair.getPrivate(), "".toCharArray(), certArray);
From there I get an error on setKeyEntry about the certificate algorithm not matching the private key algorithm. Upon inspection it seems that the Certificate object says the algo is EC and the PK object says the algo is ECDSA.
I eventually solved it this way. Note the key must be in base64 encoded DER format:
private PrivateKey convertECPrivateKeyString(String key) {
...
byte[] keyBytes = null;
if (key != null) {
keyBytes = Base64.getDecoder().decode(key);
}
try (var asnStream = new ASN1InputStream(keyBytes)) {
var primitive = asnStream.readObject();
asnStream.close();
if (primitive instanceof ASN1Sequence) {
var sequence = (ASN1Sequence) primitive;
var pKey = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(sequence);
var pkInfo = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters()), pKey);
return new JcaPEMKeyConverter().getPrivateKey(pkInfo);
}
}
...
}

Could not parse certificate: java.io.IOException: Empty input X509Certificate

I am getting the error given below when parsing the signature. Anybody has idea why the error is showing?
Note that:
Using the same certificate I signed my own XML and verified which is working fine. That mean there is no issue with certificate.
Client provided signed document not able to validate.
Errors:
Exception in thread "main" javax.xml.crypto.MarshalException: Cannot create X509Certificate
at org.jcp.xml.dsig.internal.dom.DOMX509Data.unmarshalX509Certificate(DOMX509Data.java:225)
at org.jcp.xml.dsig.internal.dom.DOMX509Data.<init>(DOMX509Data.java:116)
at org.jcp.xml.dsig.internal.dom.DOMKeyInfo.<init>(DOMKeyInfo.java:116)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.<init>(DOMXMLSignature.java:150)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshal(DOMXMLSignatureFactory.java:173)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshalXMLSignature(DOMXMLSignatureFactory.java:137)
at com.signing.ValidateSignedXML.main(ValidateSignedXML.java:126)
Caused by: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:104)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
at org.jcp.xml.dsig.internal.dom.DOMX509Data.unmarshalX509Certificate(DOMX509Data.java:223)
... 6 more
Caused by: java.io.IOException: Empty input
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:101)
Adding the code here for reference
package com.signing;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class ValidateSignedXML {
/**
* #param args
* #throws Exception
*/
/**
* #param args
* #throws Exception
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// Load the KeyStore and get the signing key and certificate.
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream("C:\\Program Files\\Java\\jre1.8.0_31\\bin\\newstore8.jks"), "changeit7".toCharArray());
KeyStore.PrivateKeyEntry keyEntry =
(KeyStore.PrivateKeyEntry) ks.getEntry
("newkey8", new KeyStore.PasswordProtection("changeit7".toCharArray()));
X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
//Load the signed document.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse
(new FileInputStream("C:\\src\\com\\signing\\signed.xml"));
// Find Signature element.
NodeList nl =
doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nl.getLength() == 0) {
throw new Exception("Cannot find Signature element");
}else{
/*System.out.println("---- Start of Print Tag ----\n");
for(int k=0;k<nl.getLength();k++){
printTags((Node)nl.item(k));
}
System.out.println("---- End of Print Tag ----\n");*/
}
// Create a DOMValidateContext and specify a KeySelector
// and document context.
DOMValidateContext valContext = new DOMValidateContext
(new X509KeySelector(), nl.item(0));
// Unmarshal the XMLSignature.
XMLSignature signatures = fac.unmarshalXMLSignature(valContext);
// Validate the XMLSignature.
boolean coreValidity = signatures.validate(valContext);
System.out.println("Signature Validate :"+coreValidity);
// Check core validation status.
if (coreValidity == false) {
String validateError;
validateError = "Signature core validation status:false";
boolean sv = signatures.getSignatureValue().validate(valContext);
validateError = validateError + " | Signature validation status:" + sv;
if (sv == false || true) {
validateError = validateError + " | References: ";
// Check the validation status of each Reference.
Iterator g = signatures.getSignedInfo().getReferences().iterator();
for (int j = 0; g.hasNext(); j++) {
Reference r = (Reference) g.next();
boolean refValid = r.validate(valContext);
validateError = validateError + "{ref[" + r.getURI() + "] validity status: " + refValid + "}";
}
}
throw new Exception(validateError);
} else {
System.out.println("Signature passed core validation");
}
}
}
It's been a while since this post but I came here looking for this issue. In my case, the key was that the certificate was in a Base64-String.getBytes[] instead of a DECODED-Base64-String.getBytes[].
Hope it helps someone :)
After going through so many blogs nothing helped as such. Finally we confirmed the way client is doing his encryption and used the same jars used for our verification. I am not sure if this is correct answer or not but may help somebody who is trying hard to resolve this issue.
It may give you some clue if not able to resolve above error after going through many sites.
So try to use same jars which used for client encryption and get the compatible private key for your public key and add to pk12 file. Convert pk12 to jks which you can use for encryption and verification too which resolved our issue.
Some process too
#**Create PKCS12 keystore from private key and public certificate.**
openssl pkcs12 -export -name myservercert -in selfsigned.crt -inkey server.key -out keystore.p12
#**Convert PKCS12 keystore into a JKS keystore**
keytool -importkeystore -destkeystore mykeystore.jks -srckeystore keystore.p12 -srcstoretype pkcs12 -alias myservercer
Good luck guys.
Error can be as simple as not having the BEGIN and END tags in your certificate set.
-----BEGIN CERTIFICATE-----
your cert data here
-----END CERTIFICATE-----

How to store a simple key string inside Java KeyStore?

I have a file on my FS (a S3 AWS key) that contains a string that is a key I use for encryption process.
I would like to move it a Java KeyStore.
I know how to import a certificate into a KeyStore with keytool but I can't find the way to import a simple string key.
Can you help?
You can do this with PBE and JCEKS. I don't think you can do it with JKS.
Solution:
Create a keystore to store and get entries from:
keytool -keystore clientkeystore -genkey -alias client -storetype jceks
Now some code to test it out.
public static String getPasswordFromKeystore(String entry, String keystoreLocation, String keyStorePassword) throws Exception{
KeyStore ks = KeyStore.getInstance("JCEKS");
ks.load(null, keyStorePassword.toCharArray());
KeyStore.PasswordProtection keyStorePP = new KeyStore.PasswordProtection(keyStorePassword.toCharArray());
FileInputStream fIn = new FileInputStream(keystoreLocation);
ks.load(fIn, keyStorePassword.toCharArray());
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE");
KeyStore.SecretKeyEntry ske =
(KeyStore.SecretKeyEntry)ks.getEntry(entry, keyStorePP);
PBEKeySpec keySpec = (PBEKeySpec)factory.getKeySpec(
ske.getSecretKey(),
PBEKeySpec.class);
char[] password = keySpec.getPassword();
return new String(password);
}
public static void makeNewKeystoreEntry(String entry, String entryPassword, String keyStoreLocation, String keyStorePassword)
throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE");
SecretKey generatedSecret =
factory.generateSecret(new PBEKeySpec(
entryPassword.toCharArray()));
KeyStore ks = KeyStore.getInstance("JCEKS");
ks.load(null, keyStorePassword.toCharArray());
KeyStore.PasswordProtection keyStorePP = new KeyStore.PasswordProtection(keyStorePassword.toCharArray());
ks.setEntry(entry, new KeyStore.SecretKeyEntry(
generatedSecret), keyStorePP);
FileOutputStream fos = new java.io.FileOutputStream(keyStoreLocation);
ks.store(fos, keyStorePassword.toCharArray());
}
I had to do this this afternoon, the solution of #JasonG works but not the keytool options.
Since Java 8 you can use the -importpass option with Keytool, which will help you achieve what you need.
Let's suppose I want to save the sensitive password foobar in the mypass alias in the keystore named myks.jceks protected with the password password here, do the following:
$ keytool -importpass -storetype pkcs12 -alias mypass -keystore myks.p12
Enter keystore password: <password>
Re-enter new password: <password>
Enter the password to be stored: <foobar>
Re-enter password: <foobar>
Enter key password for <mypass>
(RETURN if same as keystore password): <password>
Re-enter new password: <password>
And then you're good to go to use the same code as #JasonG, I have this in my code:
private Try<String> loadKey(Resource path, String pw) {
return Try.of(() -> {
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(path.getInputStream(), pw.toCharArray());
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE");
SecretKeyEntry ske = (SecretKeyEntry) ks.getEntry("mypass",
new PasswordProtection(pw.toCharArray()));
PBEKeySpec keySpec = (PBEKeySpec) factory.getKeySpec(
ske.getSecretKey(), PBEKeySpec.class);
return new String(keySpec.getPassword());
});
}
Note that I have used PKCS12 since JCEKS uses a proprietary format, and it is recommended to migrate to PKCS12 which is an industry standard format.
Besides we had some problems with some Windows machine (running Java 8) being stuck while trying to load the JCEKS store, throwing exceptions. PKCS12 seems a better choice.
I don't see a way to do it with keytool, but some poking about, I wonder if you could store and retrieve it in code as a PasswordBasedEncryption (PBE) SecretKey. (Disclaimer: I haven't tried this myself).
The resources that drove this thought:
PBEKeySpec javadoc and CryptoSpec - Using Password Based Encryption example
I know this is old; but I came across this same use case.
https://docs.oracle.com/javase/9/tools/keytool.htm#JSWOR-GUID-5990A2E4-78E3-47B7-AE75-6D1826259549
keystores have an importpass options that stores a KeyStore.SecretKeyEntry identified by alias.
So there's that and you could store your string in an alias.
You can not import in the key store arbitrary strings. In the key store you import certification keys that java libraries are using for authentication of remote hosts.

How to Load RSA Private Key From File

I am working on a test harness for a SAML 1.1 Assertion Consumer Service. The test must generate a signed SAMLResponse and submit it to the ACS encoded in Base64. The ACS must be able to verify the signed message using the X509 public cert.
I am able to build the SAMLResponse, adding the necessary assertions, etc. But when I try to sign the object I am running into problems. Here is a snippet of my current code:
String certPath = "mycert.pem";
File pubCertFile = new File(certPath);
BufferedInputStream bis = null;
try {
bis = new BufferedInputStream(new FileInputStream(pubCertFile));
} catch(FileNotFoundException e) {
throw new Exception("Could not locate certfile at '" + certPath + "'", e);
}
CertificateFactory certFact = null;
Certificate cert = null;
try {
certFact = CertificateFactory.getInstance("X.509");
cert = certFact.generateCertificate(bis);
} catch(CertificateException e) {
throw new Exception("Could not instantiate cert", e);
}
bis.close();
ArrayList<Certificate> certs = new ArrayList<Certificate>();
certs.add(cert);
String keyPath = "mykey.pem";
File privKeyFile = new File(keyPath);
try {
bis = new BufferedInputStream(new FileInputStream(privKeyFile));
} catch(FileNotFoundException e) {
throw new Exception("Could not locate keyfile at '" + keyPath + "'", e);
}
byte[] privKeyBytes = new byte[(int)privKeyFile.length()];
bis.read(privKeyBytes);
bis.close();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new PKCS8EncodedKeySpec(privKeyBytes);
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(ks);
samlResponse.sign(Signature.getInstance("SHA1withRSA").toString(), privKey, certs);
The error occurs on the second-to-last line. I see the following in the console:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
Though not customary or secure, but for sake of this thread, I am providing the public cert and private key that I am using. I of course will re-create new ones once the problem is solved. :)
aj#mmdev0:~/$ cat mykey.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDnbcLSlDFaDMhalcmQgclTFobpkHQHJtxMVGRlbv7zknttAVbY
1jzGjJ6HVupndzDxA9tbiMjQujmGlS/8g5IEbVsR9o6dmcmbvujtEZ2rHZ82tMYP
VAt2IoS/W/q2Rr1cAZ/zTKEmh0ZZjzCZFueLfrYPm3am5JLcXgVtbKwybQIDAQAB
AoGBAJ441oettYgBUUFNQv8/HGtn7Vjl38277cVptTH8DuZr8WJ3Fe8tmWONZBzX
eW6/eIBuyJvuCo1ZpFa0zJfxQ/Ph6QlQwdN50GNfh9RzSS6lDdfy8BRhc27sypXS
L6c5ljB6ql+pp3DdxFhJMOs3ZmBJdeyWe7uFrkngtnM1nxZBAkEA+1hbV1Q305wa
u8YMF1SlNIAfgLJ7buD43SEXle0egz405PFG8f8yDmvROwDiRceILGVrRbInd7Cb
dvJKr34WOQJBAOu2+reG44rNuiXeGX1MYg6TlWYyABm7PrTrhPZkedodOQB8p7zD
AqtDSK7RnDCoThndPW6kdNAeB+kG4ug5XdUCQHRDU8UajNRSkj8nhjJIkj6twWS7
qsMIR7Wp+An+7C1TWg5I2UNZg2MOVnNPnlseyAuZQjy0AvOnetJTk16IGWkCQQCL
FUbOr8rnhgiGe4yywDVDwJVw3aPtiuyvOCEWeabkqkWOIf+fg7m5cFQcwxXUKBsd
a8vp0yQSAQZN24Bb4i2ZAkEA8xGJFlFDY9HREWZnDey5STgbUeT1wYkyKcDsUrp1
kR/3BliGqSIfje+mSKDIZqaP+gai/8bIABYAsDP/t6+cuA==
-----END RSA PRIVATE KEY-----
aj#mmdev0:~/$ cat mycert.pem
-----BEGIN CERTIFICATE-----
MIID7zCCA1igAwIBAgIJAKrURaAaD6ulMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xHDAa
BgNVBAoTE0hvc3R3YXkgQ29ycG9yYXRpb24xITAfBgNVBAsTGFJlc2VhcmNoIGFu
ZCBEZXZlbG9wbWVudDEYMBYGA1UEAxMPd3d3Lmhvc3R3YXkuY29tMR0wGwYJKoZI
hvcNAQkBFg5hakBob3N0d2F5LmNvbTAeFw0xMDA3MTQwMjMyMDhaFw0xMTA3MTQw
MjMyMDhaMIGsMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
BAcTB0NoaWNhZ28xHDAaBgNVBAoTE0hvc3R3YXkgQ29ycG9yYXRpb24xITAfBgNV
BAsTGFJlc2VhcmNoIGFuZCBEZXZlbG9wbWVudDEYMBYGA1UEAxMPd3d3Lmhvc3R3
YXkuY29tMR0wGwYJKoZIhvcNAQkBFg5hakBob3N0d2F5LmNvbTCBnzANBgkqhkiG
9w0BAQEFAAOBjQAwgYkCgYEA523C0pQxWgzIWpXJkIHJUxaG6ZB0BybcTFRkZW7+
85J7bQFW2NY8xoyeh1bqZ3cw8QPbW4jI0Lo5hpUv/IOSBG1bEfaOnZnJm77o7RGd
qx2fNrTGD1QLdiKEv1v6tka9XAGf80yhJodGWY8wmRbni362D5t2puSS3F4FbWys
Mm0CAwEAAaOCARUwggERMB0GA1UdDgQWBBQI/4Inzs6OH5IquItuKhIrhPb24zCB
4QYDVR0jBIHZMIHWgBQI/4Inzs6OH5IquItuKhIrhPb246GBsqSBrzCBrDELMAkG
A1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGljYWdvMRww
GgYDVQQKExNIb3N0d2F5IENvcnBvcmF0aW9uMSEwHwYDVQQLExhSZXNlYXJjaCBh
bmQgRGV2ZWxvcG1lbnQxGDAWBgNVBAMTD3d3dy5ob3N0d2F5LmNvbTEdMBsGCSqG
SIb3DQEJARYOYWpAaG9zdHdheS5jb22CCQCq1EWgGg+rpTAMBgNVHRMEBTADAQH/
MA0GCSqGSIb3DQEBBQUAA4GBAA388zZp6UNryC/6o44hj7wTBQdzFFM5cs3B668A
ylAnnal+J8RMIeCHoMF4S7yFQtYdOiWeScgw3c7KXrhJK1X7fU3I+eb1t3Yp1cTI
htyzw14AoiICFalmlVgTCsn3+uh6AXP02PTkR8osdEpUOlWap4uzSKYNKc7tLOFd
4CkM
-----END CERTIFICATE-----
Thanks!
You need to convert your private key to PKCS8 format using following command:
openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key_file -nocrypt > pkcs8_key
After this your java program can read it.
Two things. First, you must base64 decode the mykey.pem file yourself. Second, the openssl private key format is specified in PKCS#1 as the RSAPrivateKey ASN.1 structure. It is not compatible with java's PKCS8EncodedKeySpec, which is based on the SubjectPublicKeyInfo ASN.1 structure. If you are willing to use the bouncycastle library you can use a few classes in the bouncycastle provider and bouncycastle PKIX libraries to make quick work of this.
import java.io.BufferedReader;
import java.io.FileReader;
import java.security.KeyPair;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
// ...
String keyPath = "mykey.pem";
BufferedReader br = new BufferedReader(new FileReader(keyPath));
Security.addProvider(new BouncyCastleProvider());
PEMParser pp = new PEMParser(br);
PEMKeyPair pemKeyPair = (PEMKeyPair) pp.readObject();
KeyPair kp = new JcaPEMKeyConverter().getKeyPair(pemKeyPair);
pp.close();
samlResponse.sign(Signature.getInstance("SHA1withRSA").toString(), kp.getPrivate(), certs);

How to connect to a secure website using SSL in Java with a pkcs12 file?

I have a pkcs12 file. I need to use this to connect to a webpage using https protocol. I came across some code where in order to connect to a secure web page i need to set the following system properties:
System.setProperty("javax.net.ssl.trustStore", "myTrustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
System.setProperty("javax.net.ssl.keyStore", "new_cert.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "newpass");
I have the p12(pkcs12) file. All I need is a truststore file.
I extracted the certificates using:
openssl.exe pkcs12 -in c:/mykey.p12 -out c:/cert.txt -nokeys -clcerts
Now converted the cert PEM file to der
openssl.exe x509 -in c:/cert.txt -outform DER -out c:/CAcert.der
Now adding the der file to a keystore
keytool -import -file C:/Cacert.der -keystore mytruststore
Now I have the truststore, but when I use it, I get the following error
Exception in thread "main" java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
Update:
After removing certain properties and setting only the "trustStore", "trustStorePassword" and "trustStoreType" property, I got the following exception
java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
Please Help.
For anyone encountering a similar situation I was able to solve the issue above as follows:
Regenerate your pkcs12 file as follows:
openssl pkcs12 -in oldpkcs.p12 -out keys -passout pass:tmp
openssl pkcs12 -in keys -export -out new.p12 -passin pass:tmp -passout pass:newpasswd
Import the CA certificate from server into a TrustStore ( either your own, or the java keystore in $JAVA_HOME/jre/lib/security/cacerts, password: changeit).
Set the following system properties:
System.setProperty("javax.net.ssl.trustStore", "myTrustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
System.setProperty("javax.net.ssl.keyStore", "new.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "newpasswd");
Test ur url.
Courtesy# http://forums.sun.com/thread.jspa?threadID=5296333
I cannot comment because of the 50pts threshhold, but I don't think that the answer provided in https://stackoverflow.com/a/537344/1341220 is correct.
What you are actually describing is how you insert server certificates into the systems default truststore:
$JAVA_HOME/jre/lib/security/cacerts, password: changeit)
This works, indeed, but it means that you did not really specify a trust store local to your project, but rather accepted the certificate universially in your system.
You actually never use your own truststore that you defined here:
System.setProperty("javax.net.ssl.trustStore", "myTrustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
It appears that you are extracting you certificate from the PKCS #12 key store and creating a new Java key store (with type "JKS"). You don't strictly have to provide a trust store password (although using one allows you to test the integrity of your root certificates).
So, try your program with only the following SSL properties set. The list shown in your question is over-specified and may be causing problems.
System.setProperty("javax.net.ssl.trustStore", "myTrustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
Also, using the PKCS #12 file directly as the trust store should work, as long as the CA certificate is detected as a "trusted" entry. But in that case, you'll have to specify the javax.net.ssl.trustStoreType property as "PKCS12" too.
Try with these properties only. If you get the same error, I suspect your problem is not the key store. If it still occurs, post more of the stack trace in your question to narrow the problem down.
The new error, "the trustAnchors parameter must be non-empty," could be due to setting the javax.net.ssl.trustStore property to a file that doesn't exist; if the file cannot be opened, an empty key store created, which would lead to this error.
This is an example to use ONLY p12 file it's not optimazed but it work.
The pkcs12 file where generated by OpenSSL by me.
Example how to load p12 file and build Trust zone from it...
It outputs certificates from p12 file and add good certs to TrustStore
KeyStore ks=KeyStore.getInstance("pkcs12");
ks.load(new FileInputStream("client_t_c1.p12"),"c1".toCharArray());
KeyStore jks=KeyStore.getInstance("JKS");
jks.load(null);
for (Enumeration<String>t=ks.aliases();t.hasMoreElements();)
{
String alias = t.nextElement();
System.out.println("#:" + alias);
if (ks.isKeyEntry(alias)){
Certificate[] a = ks.getCertificateChain(alias);
for (int i=0;i<a.length;i++)
{
X509Certificate x509 = (X509Certificate)a[i];
System.out.println(x509.getSubjectDN().toString());
if (i>0)
jks.setCertificateEntry(x509.getSubjectDN().toString(), x509);
System.out.println(ks.getCertificateAlias(x509));
System.out.println("ok");
}
}
}
System.out.println("init Stores...");
KeyManagerFactory kmf=KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "c1".toCharArray());
TrustManagerFactory tmf=TrustManagerFactory.getInstance("SunX509");
tmf.init(jks);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
URL url = new URL("https://test.domain:443");
String keyStore = "server.p12"
String keyStorePassword = "changeit";
String keyPassword = "changeit";
String KeyStoreType= "PKCS12";
String KeyManagerAlgorithm = "SunX509";
String SSLVersion = "SSLv3";
public HttpURLConnection getHttpsURLConnection(URL url, String keystore,
String keyStorePass,String keyPassword, String KeyStoreType
,String KeyManagerAlgorithm, String SSLVersion)
throws NoSuchAlgorithmException, KeyStoreException,
CertificateException, FileNotFoundException, IOException,
UnrecoverableKeyException, KeyManagementException {
System.setProperty("javax.net.debug","ssl,handshake,record");
SSLContext sslcontext = SSLContext.getInstance(SSLVersion);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerAlgorithm);
KeyStore ks = KeyStore.getInstance(KeyStoreType);
ks.load(new FileInputStream(keystore), keyStorePass.toCharArray());
kmf.init(ks, keyPassword.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
TrustManager[] tm = tmf.getTrustManagers();
sslcontext.init(kmf.getKeyManagers(), tm, null);
SSLSocketFactory sslSocketFactory = sslcontext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
HttpsURLConnection httpsURLConnection = ( HttpsURLConnection)uRL.openConnection();
return httpsURLConnection;
}
This example shows how you can layer SSL on top of an existing socket, obtaining the client cert from a PKCS#12 file. It is appropriate when you need to connect to an upstream server via a proxy, and you want to handle the full protocol by yourself.
Essentially, however, once you have the SSL Context, you can apply it to an HttpsURLConnection, etc, etc.
KeyStore ks = KeyStore.getInstance("PKCS12");
InputStream is = ...;
char[] ksp = storePassword.toCharArray();
ks.load(is, ksp);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
char[] kp = keyPassword.toCharArray();
kmf.init(ks, kp);
sslContext = SSLContext.getInstance("SSLv3");
sslContext.init(kmf.getKeyManagers(), null, null);
SSLSocketFactory factory = sslContext.getSocketFactory();
SSLSocket sslsocket = (SSLSocket) factory.createSocket(socket, socket
.getInetAddress().getHostName(), socket.getPort(), true);
sslsocket.setUseClientMode(true);
sslsocket.setSoTimeout(soTimeout);
sslsocket.startHandshake();
The following steps will help you to sort your problem out.
Steps:
developer_identity.cer <= download from Apple
mykey.p12 <= Your private key
Commands to follow:
openssl x509 -in developer_identity.cer -inform DER -out developer_identity.pem -outform PEM
openssl pkcs12 -nocerts -in mykey.p12 -out mykey.pem
openssl pkcs12 -export -inkey mykey.pem -in developer_identity.pem -out iphone_dev.p12
Final p12 that we will require is iphone_dev.p12 file and the passphrase.
use this file as your p12 and then try. This indeed is the solution.:)
I realise that this article may be outdated but still I would like to ask smithsv to correct his source code, it contains many mistakes, I managed to correct most of them but still don't know what kind of object x509 could be.Here is the source code as I think is should be:
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.util.Enumeration;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
public class Connection2 {
public void connect() {
/*
* This is an example to use ONLY p12 file it's not optimazed but it
* work. The pkcs12 file where generated by OpenSSL by me. Example how
* to load p12 file and build Trust zone from it... It outputs
* certificates from p12 file and add good certs to TrustStore
*/
KeyStore ks = KeyStore.getInstance( "pkcs12" );
ks.load( new FileInputStream( cert.pfx ), "passwrd".toCharArray() );
KeyStore jks = KeyStore.getInstance( "JKS" );
jks.load( null );
for( Enumeration t = ks.aliases(); t.hasMoreElements(); ) {
String alias = (String )t.nextElement();
System.out.println( "#:" + alias );
if( ks.isKeyEntry( alias ) ) {
Certificate[] a = ks.getCertificateChain( alias );
for( int i = 0; i == 0; )
jks.setCertificateEntry( x509Cert.getSubjectDN().toString(), x509 );
System.out.println( ks.getCertificateAlias( x509 ) );
System.out.println( "ok" );
}
}
System.out.println( "init Stores..." );
KeyManagerFactory kmf = KeyManagerFactory.getInstance( "SunX509" );
kmf.init( ks, "c1".toCharArray() );
TrustManagerFactory tmf = TrustManagerFactory.getInstance( "SunX509" );
tmf.init( jks );
SSLContext ctx = SSLContext.getInstance( "TLS" );
ctx.init( kmf.getKeyManagers(), tmf.getTrustManagers(), null );
}
}

Categories