Is it possible to change the certificate and certificate chain for existing entry (private key) in keystore. As I understand, firstly I need to delete existing entry and then store same private key with new certificate and chain. This solution is not an option since I don't know the password for that entry in keystore.
Solution so far:
Key generation and initial storage:
KeyPair kp = generateRSAKeyPair();
X509Certificate selfSignedCert = makeSelfSignedCert(kp);
ks.load(...);
ks.setKeyEntry("entry1", kp.getPrivate(), PASSWORD, new X509Certificate[]{selfSignedCert});
ks.store(...);
After CA sends certificate I want:
ks.load(...);
ks.setCertificateEntry("entry1", caSignedCert);
ks.store(...);
The main issue is that I don't have the right certificate at the time when the key is being stored to keystore. There is a delay between the generation of keys and when CA sends signed certificates.
Another option would be to not set certificate at all, and after CA signs CSR, add the final signed certificate to keystore. Something like:
KeyPair kp = generateRSAKeyPair();
ks.load(...);
ks.setKeyEntry("entry1", kp.getPrivate(), PASSWORD);
ks.store(...);
// after some time
ks.load(...);
ks.setCertificateEntry("entry1", caSignedCert);
ks.store(...);
But I couldn't find a way to store private key without an associated certificate in keystore. Storing private key elsewhere else is also not an option.
A potential solution is to store signed certificate from CA until a user provides the password to keystore entry and then deleting existing entry & creating new entry with proper certificates. This solution is not ideal and I would like to avoid going down this road.
Any suggestions are welcome.
The solution is to first store key to keystore with the self-signed certificate. At this time, this key cannot be used because CA did not sent the proper certificate for this key yet. If one would use key at this time for signing, the associated self-signed certificate would be used (which is not desirable).
After some time CA sends the proper certificate, which must be stored somewhere (database in my case).
On the first opportunity when the password for key entry is supplied, key is retrieved from keystore and immediately gets stored again with the same password but different alias and proper certificate from CA. Then it is safe to delete original entry with self-signed certificate.
I hope this helps someone. Any better solutions are welcome.
Related
I am receiving the following String from a certificate stored in Azure Key Vault. I am using the Secret API in order to retrieve both the certificate and the private key related to this cert.
Initially the certificate was uploaded using a .pfx file to Azure Key vault. Now I need to create a Certificate and a PrivateKey to allow client authentication to a 3rd party system and I am using the given String retrieved from the API, however I am note sure how to get around that in Java.
I took some hints from this link in C# however I am pretty certain that this method doesn't work like that in Java. In particular an X509Certificate or a Certificate in general doesn't hold any information about the PrivateKey in Java, unlike C#, and I am not sure how to extract that information from given String in Java.
This works as expected to retrieve the certificate from the String retrieved from the API
String secret = azureSecret.getValue();
byte[] certkey = Base64.getDecoder().decode(secret);
ByteArrayInputStream inputStream = new ByteArrayInputStream(certkey);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(inputStream);
The azureSecret.getValue() format is like the following however I am not sure how to get PrivateKey out of the given String
MIIKvgIBaaZd6Euf3EYwYdHrIIKYzCC...
YES, Java X509Certificate and Certificate is only the certificate. Instead use KeyStore which can contain multiple entries each of which is either a 'trusted' certificate (for someone else), or a privatekey plus certificate plus other chain cert(s) (if applicable) for yourself, or (not relevant here) a 'secret' (symmetric) key. PKCS12 is supported as one type of KeyStore along with others not relevant here, so after the base64-decoding you already have do something like:
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(inputstreamfromvaultvalue, password);
// then
PrivateKey pkey = (PrivateKey) ks.getKey(alias, password);
// and
Certificate cert = ks.getCertificate(alias); // if you only need the leaf cert
// or
Certificate[] chain = ks.getCertificateChain(alias); // usually
But if you want to do client authentication in TLS/SSL (including HTTPS), you give the JSSE KeyManager the whole keystore object not the individual pieces (privatekey and certificates). Similarly to verify the peer in TLS/SSL, you give TrustManager a keystore containing trusted certificates, usually root CAs and often defaulted to a built-in set of public root CAs.
To build an apk we need a certificate, this certificate contains the public key and also some metadata (like Company, …). The certificate itself is generated through the app signing key.
The app signing key is exactly the same as a keystore entity or? (what I think for now)
And what does one keystore entity contains exactly?
Does a keystore entity stores the „private key + public key + metadata“ inside one entity?
or the „private key + metadata (separate)“ and generates the public key through the private key?
or only a „private key“ where the metadata are written in and generates the public key through the private key?
Or otherwise? I would really like to know more technical based informations about a keystore entity/app signing key and couldn’t find a more detailed (technical based) description of storage and generation.
Thank you
Google:
"A keystore is a binary file that contains one or more private keys“
"Generate Signed APK […], select a keystore, a private key, and enter the passwords for both.“
https://developer.android.com/studio/publish/app-signing.html
A keystore is a container for keys and certificates. An Android Keystore contains the app signing key and the matching certificate.
A cryptographic key pair, public and private is generated randomly. The public key is embedded in an X509 certificate along with some additional attributes such as serial number or common name. The certificate is signed with the private key to ensure the origin and integrity. See Certificate enrollment process
Finally the private key and the certificate can be imported into a keystore file: JKS, BKS or PKCS#12
The apk is digitally signed using the private key contained in the keystore, and the certificate is also included, so you could verify the identity of the signatory and the integrity of the package
I've been asked to create a jks keystore based on a certificate we had created. I've read a bit on the topic, but I'm still confused on a few items:
Is the private key of a certificate supposed to be stored in a .jks keystone?
If yes - where does this get entered in? Using the keytool, it doesn't require one for creating a jks file.
If no - what is the purpose of a jks file? Why would my application need it instead of just reading in a certificate directly? And why does the keytool require a password to create a jks if it just contains a public key?
The purpose of a key store is to protect the privacy and integrity of cryptographic keys using password-based algorithms. Privacy means that the keys are kept secret; they can only be used by someone who knows the password; this is useful for private keys and secret keys. Integrity means that alteration of the keys can be detected by someone who knows the password; this is useful for public keys and secret keys.
Whether you should include the private key or not depends on what you are trying to do. If you are creating a key store for your server so that it can authenticate itself to clients, for example, then it should contain the private key. If you created a self-signed certificate, and want to give clients a key store so that they can authenticate your service, then it should not contain the private key.
If you have a pre-existing key pair, and want to import it to a JKS format key store, the easiest way might be to use OpenSSL to create a PKCS #12 format key store, then use keytool to convert that to a JKS key store. Normally, keytool expects to do key pair generation itself, and so the private key will be stored there from the beginning.
You should verify the integrity of a public key or a certificate before you use it to encrypt a message or verify a signature. Otherwise, an attacker can replace the key with one he owns and act as a man in the middle. If you simply read a public key from a file, you don't know it really belongs to your intended recipient. But if you store a password-based message authentication code with the public key, you can ensure that it hasn't been tampered with.
Is the private key of a certificate supposed to be stored in a .jks keystone?
Yes, if you own the certificate and it is stored there.
If yes - where does this get entered in? Using the keytool, it doesn't require one for creating a jks file.
That's because you can also use it as a truststore, which only contains trusted certificates.
To get the private key in there you will need to first convert it and its certificate to a PKCS#12 file using openssl, as answered in numerous questions here such as this.
If no - what is the purpose of a jks file? Why would my application need it instead of just reading in a certificate directly?
Because your application also needs the private key of the certificate.
And why does the keytool require a password to create a jks if it just contains a public key?
A keystore has a password because it is a security-related entity.
I would like to know how can I rename an alias of a keystore, programmatically in java, not using keytool.
I have my java.security.KeyStore object, containing an certain alias. How can I rename it?
The KeyStore API does not provide a rename operation for aliases. But what you can do is:
Save the content (key pair, certificates) of the keystore entry that you want to rename.
Delete the entry.
Create a new entry with the saved content and the new alias.
As Java code:
Key privateKey = keyStore.getKey(alias, password.toCharArray());
Certificate[] certs = keyStore.getCertificateChain(alias);
keyStore.setKeyEntry(newAlias, privateKey, password.toCharArray(), certs);
keyStore.deleteEntry(alias);
Of course this does not work if the private key is stored on a hardware device (smartcard or HSM) and therefore is not readable.
If the keystore entry contains a trusted certificate, the code looks a bit different:
Certificate cert = keyStore.getCertificate(alias);
keyStore.setCertificateEntry(newAlias, cert);
keyStore.deleteEntry(alias);
I'm required to create a program that validate any given X509 Certificate Version3 if it is trusted or not by verifying the signature. In order to to do that, I need to be able to know the issuer's public key who has signed that given certificate. I know how to output the issuer information using getIssuerDN() method but what I don't know is how to get the issuer's public key when I only know its name !
The only solution I have so far is to maintain a list of public keys for the most common Certificate Authorities on the web, and just search through it. Although this solution is doable, it seems impractical to me.
Therefore, is there another idea to get the Issuer's public key from a certificate directly and then complete the process of verification ?
Here is my code for getting the Issuer's name but NOT its public key.
URL url = new URL("https link here!");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.connect();
Certificate cert[] = con.getServerCertificates();
X509Certificate x509cert = (X509Certificate) cert[0];
String[] st= x509cert.getIssuerDN().toString().split(",");
System.out.println("Issuer CN is: "+st[0].toString());
I'm required to create a program that validate any given X509 Certificate Version3 if it is trusted or not by verifying the signature. In order to to do that, I need to be able to know the issuer's public key who has signed that given certificate.
No. Either you or whoever gave you the assignment doesn't understand PKI. The idea is that you already trust some issuers by virtue of already having their certificates, e.g. in the cacerts file distributed with the JRE, and therefore their public keys. If the certificate you're asked to verify is traceable to one of these issuers and it passes all other verifications, you can trust it. Mere verification via the public key alone is not sufficient.