Saving Signed X509Certificate and PrivateKey in Android - java

I would like to save a X509Certificate and its private key into the Android KeyStore, I tought I should 'merge' the X509Certificate (containing the public key) and its private key. The private key is used to create a CSR and then a server party sign the certificate and return to the application, can I merge the cert and the private key into one unique cert? Also I'm using spongycastle (aka bouncycastle's android wrapper).

I have no idea about Android KeyStore, but maybe you can try something like:
PrivateKey privateKey = ... //this is what you already have
X509Certificate certificate = ... //this is what you already have
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
Certificate[] certChain = new Certificate[1];
certChain[0] = certificate;
char[] myKeyPassword = "myKeyPassword".toCharArray();
keyStore.setKeyEntry("mykeyalias", (Key)privateKey, myKeyPassword, certChain);
See https://docs.oracle.com/javase/9/docs/api/java/security/KeyStore.html#setKeyEntry-java.lang.String-java.security.Key-char:A-java.security.cert.Certificate:A- for more information about KeyStore.setKeyEntry

Related

Programatically convert a JKS to PEM

I need to convert a JKS (password protected) in to a .PEM containing the KeyPairs (or selected alias) for other services to use.
So far, I have written this:
#Transactional
public ResponseEntity<String> getPublicKeyFromJKS(long jksid) {
try {
//1. Lift the entity
JKSFile jksFile = jksFileRepo.getOne(jksid);
//2. Get the Object from S3
S3Object object = getS3ObjectService.getS3Object(jksFile.getS3ObjectKey());
System.out.println(object.getObjectContent().getHttpRequest());
InputStream in = object.getObjectContent();
//3. Make KeyStore...
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(in, rsaConfig.getKeystorePassword().toCharArray());
//4. Get keys to PEM formatted file.
PrivateKey privateKey = (PrivateKey) keyStore.getKey("access", rsaConfig.getKeystorePassword().toCharArray());
Certificate certificate = keyStore.getCertificate("access");
PublicKey publicKey = certificate.getPublicKey();
KeyPair keyPair = new KeyPair(publicKey, privateKey);
System.out.println(keyPair.getPrivate().toString());
System.out.println(keyPair.getPublic().toString());
I am pulling the requested JKS from my amazon S3 bucket and reading the Private and Public key without issue...but I would now like to be able to put them in to a PEM formatted keystore (for use by another service).
Thanks for any suggestions! I want this programatically...not using the java command line keytool.

Use of isKeyEntry(alias) in KeyStore - Java

I wanted to load the keystore file and get the details of its root SSL Certificate.
Link to Sample
I saw the code in the above link. The code is also visible below. What is the use of keyStore.isKeyEntry(alias)?
I check JavaDocs and it says
Returns true if the entry identified by the given alias was created by a call to setKeyEntry, or created by a call to setEntry with a PrivateKeyEntry or a SecretKeyEntry.
So, What is the use of it?
boolean isAliasWithPrivateKey = false;
KeyStore keyStore = KeyStore.getInstance("JKS");
// Provide location of Java Keystore and password for access
keyStore.load(new FileInputStream(jksPath), jksPassword.toCharArray());
// iterate over all aliases
Enumeration<String> es = keyStore.aliases();
String alias = "";
while (es.hasMoreElements()) {
alias = (String) es.nextElement();
// if alias refers to a private key break at that point
// as we want to use that certificate
if (isAliasWithPrivateKey = keyStore.isKeyEntry(alias)) {
break;
}
}
if (isAliasWithPrivateKey) {
KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias,
new KeyStore.PasswordProtection(jksPassword.toCharArray()));
PrivateKey myPrivateKey = pkEntry.getPrivateKey();
// Load certificate chain
Certificate[] chain = keyStore.getCertificateChain(alias);
certDetails = new CertificateDetails();
certDetails.setPrivateKey(myPrivateKey);
certDetails.setX509Certificate((X509Certificate) chain[0]);
}
You have 3 types of entries in a java keystore:
privateKeyEntry, private key and associated certificate chain
trustedKeyEntry, a trusted certificate (e.g. certificate from CA like Verisign, GoDaddy ...)
secretKeyEntry, a encryption key (e.g. a symmetric key AES)
as described in the java docs, KeyStore.isKeyEntry(alias) returns true is you have secret or a private key.
The code example will fail if the entry is a secret key:
`KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(jksPassword.toCharArray()));`
it would be preferable to use:
`KeyStore.entryInstanceOf(alias , KeyStore.PrivateKeyEntry.class)`

Reading CA Cert Private Key to Sign Certificate

I have a requirement as below:
Create a self signed (say CA cert) and save the cert and private key
to files
Load the CA Cert (Created in Step 1) and its private key
Create a end
certificate which is signed using CA Cert and Private Key loaded in
Step 2
My Private Key is Stored to a file as below:
public static void writePrivateKey(PrivateKey privateKey, OutputStream os) throws IOException
{
BufferedOutputStream bos = new BufferedOutputStream(os);
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
privateKey.getEncoded());
bos.write(pkcs8EncodedKeySpec.getEncoded());
bos.close();
}
My private Key is loaded back as below:
public PrivateKey loadPrivatekey(InputStream privateKeyInputStream)
throws InvalidKeySpecException, NoSuchAlgorithmException, IOException
{
return KeyFactory.getInstance(algorithamForCreatingAndLoadingKeys)
.generatePrivate(new PKCS8EncodedKeySpec(IOUtils.toByteArray(privateKeyInputStream)));
}
I have my algorithm defined as RSA
private String algorithamForCreatingAndLoadingKeys = "RSA";
Iam signing my certificate as below:
private static X509CertImpl buildAndSignCert(X509CertInfo certInfo, PrivateKey privateKey)
throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException, IOException
{
X509CertImpl cert = new X509CertImpl(certInfo);
String algorithm = "SHA1withRSA";
// Sign the cert to identify the algorithm that's used.
cert.sign(privateKey, algorithm);
// Update the algorith, and resign.
certInfo.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM,
cert.get(X509CertImpl.SIG_ALG));
X509CertImpl newCert = new X509CertImpl(certInfo);
newCert.sign(privateKey, algorithm);
return newCert;
}
Problem: If i create the CA cert and end certificate without saving and loading the key file I was able to validate the end certificate fine:
C:\Workspace.....\src\main\resources>openssl verify -CAfile ca.pem end.pem
end.pem: OK
But If i save and load the key files and verify, I get below error, which clearly says that my end certificate is not signed correct with my ca cert
C:\Workspace.....\src\main\resources>openssl verify -CAfile ca.pem
end.pem
end.pem: C = AU, L = ABC, CN = XYZ
error 20 at 0 depth lookup:unable to get local issuer certificate
So, Iam coming to the conclusion that my saving of private key and loading it is buggered.
Can any one pleas help what Iam doing wrong in saving and reading private keys ?
Many Thanks in advance.
All the code that I have posted above is correct and accurate to create and read a private key file.
I have spotted the problem to be with loading the Created CA Cert itself (not the private key), some how when we generate X509 Certificate as below:
CertificateFactory f = CertificateFactory.getInstance("X.509");
X509Certificate loadedCaCert = (X509Certificate) f
.generateCertificate(CertificateGenerator.class.getResourceAsStream("/ca.pem"));
the serial number that it is producing out of X509Certificate generated above is not the same as the one I passed when creating CA certtificate (Which is another issue but not realted to thsi thread anyways) and as we pass this serial number to subscriber certificate to identify its parent CA for certificate linking its failing.
Thank You

Generating certification chain

I need to generate certification chain in my java application becouse its needed when storing privatekey to keystore? Can anybody help me out. I have no idea how to do it..
I need to generate RSA keypair and then store it to keystore. Right now my code looks like this:
public static void main(String[] args)
{
String issuerDN = null;
String addKeyName = "mynewkey";
String delKeyName = null;
String password = "2222";
boolean listStore = true;
boolean deleteKeysAftherWrap = false;
try
{
/* make sure that we have access to the eracom provider */
Provider p = new ERACOMProvider();
Security.addProvider(p);
int keySize = 1024;
KeyPair keyPair = null;
/* get the eracom keystore - access to the adapter */
KeyStore keyStore = KeyStore.getInstance("CRYPTOKI", p.getName());
/* LOAD the keystore from the adapter */
keyStore.load(null, password.toCharArray());
if (addKeyName != null)
{
/* This key cannot be added to the keystore if it already exists */
if (keyStore.containsAlias(addKeyName))
{
println("");
println("Key name already exists");
println("");
}
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", p.getName());
keyPairGenerator.initialize(keySize);
keyPair = keyPairGenerator.generateKeyPair();
PublicKey pubKey = keyPair.getPublic();
PrivateKey privKey = keyPair.getPrivate();
keyStore.setKeyEntry("newpub", pubKey, null, null);
keyStore.setKeyEntry("newpriv", privKey, null, null});
}
the keys are generated but it asks certification chain for storing private key.
And that is the problem right now. How can i generate the certification chain, do i have to generate certifications first, when yes then how?
Not sure what are you trying to achieve, but some time ago I've used this little app (source code included) to insert an existing private key into a keystore. Hopefully you'll find this useful: http://www.agentbob.info/agentbob/79-AB.html
I believe the post http://www.pixelstech.net/article/1406726666-Generate-certificate-in-Java----2 will show you how to generate certificate chain with pure Java. It doesn't require you to use Bouncy Castle.
This post will show you how to generate a certificate chain which has a length longer than 1. While most posts on the Internet will show you creating a certificate chain of length 1 or using BC.

Get privatekey from Keystore

I have the following code to export certificates and keys from a keystore, that I created with keytool in Windows:
final KeyStore keystore = KeyUtil.loadKeystore("keystore.jks", "pass");
UserInfo userinfo = new UserInfo(WSusername, WSpassword);
X509Certificate clientcert = KeyUtil.getCertificate(CLIENT_KEY_ALIAS, keystore);
X509Certificate servercert = KeyUtil.getCertificate(SERVER_KEY_ALIAS, keystore);
PrivateKey clientprivate = KeyUtil.getPrivateKey(CLIENT_KEY_ALIAS, CLIENT_KEY_PASSWORD, keystore);
Yet it fails at the last line with "unable to retrieve private key for signing"
It can retrieve the clientcert, but when it tries clientprivate, it fails.
My problem was that when I generated the keystore with keytool, it did not create the PrivateKey as a key entry. To fix this, I imported the .p12 keystore as the private key, which worked. My original code above then worked.

Categories