I'm reading the certificate file with the following methods :
File certFile = new File("E:/mycert.cer");
InputStream stream = new FileInputStream(certFile);
CertificateFactory factory = CertificateFactory.getInstance("X509");
X509Certificate certificate = (X509Certificate) factory.generateCertificate(stream);
how to get the root certificate of the certificate with java programming.?
How to get sub-root certificates in the certificate?
You can't. They aren't in the certificate. You need to:
Have a stream that contains a certificate chain, not just a single certificate, and
Call generateCertificates() instead of generateCertificate(), so as to get a Collection<? extends Certificate>, or
Call generateCertPath() so as to get a CertPath, which contains an ordered List of Certificate, from which you can get the root, the leaf, and the intermediates.
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.
I am new to the world of PKI , certificates in general. I am writing a service which needs to validate a chain of certiticates.
The general approach taken is as follows
a) Generate a List of certificates from the data sent
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
CertPathValidatorResult certPathValidatorResult = null;
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
List<X509Certificate> x509Certificates =
(List<X509Certificate>) certificateFactory.generateCertificates(byteArrayInputStream);
CertPath certPath = certificateFactory.generateCertPath(x509Certificates);
Load the JDK keystore, with something like this
//Load the JDK's cacerts keystore file
String filename =
System.getProperty("java.home")
+ "/lib/security/cacerts".replace('/', File.separatorChar);
FileInputStream is = new FileInputStream(filename);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = "changeit";
keystore.load(is, password.toCharArray());
CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
PKIXParameters pkixParameters = new PKIXParameters(keystore);
//pkixParameters.setRevocationEnabled(false);
PKIXParameters certPathValidatorResult = certPathValidator.validate(certPath, pkixParameters);
I am assuming if this is not a valid chain it would throw an exception. Would this validation check expired Certificates, Valid Public Key ?
also I need to be able to find the the OCSP staus of a certificate or check if it is revoked>? How can this be done using the Cryptography API
Is the use fo bouncy castle recommended over the API ? Does Bouncy castle have a way to check CRL and OCSP status of a certificate?
Thanks for all the pointers and help in advance. Appreciate it.
Best Regards
It's correct, you can use CertificateFactory to load certificates chain.
If you want validate a chain of certiticates, you don't need a KeyStore. The certificates are validated with the certificate of autority who emit that certificate.
For example:
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(chain.getBytes());
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
List<X509Certificate> x509Certificates = (List<X509Certificate>) certificateFactory.generateCertificates(byteArrayInputStream);
x509Certificates.get(1).verify(x509Certificates.get(0).getPublicKey());
In this case you can use it to validate a certificate if you don't know the root ca.
You can check the period with
x509Certificates.get(1).getNotBefore()
and
x509Certificates.get(1).getNotAfter()
Is important validate the status of certificate.
Yes BouncyCastle is great library for it.
Suppose, there is an external CA. Let's say there is an URL and other config parameters.
In runtime I obtain a chain of certificates I need to validate using the CA.
So root certificate of the chain must be registered somehow in the CA. Also the CA handles CRL and some of the certificates in the chain could be revoked.
I have code like this
CertificateFactory cf = CertificateFactory.getInstance(certificateType);
List<Certificate> certx = //list of certificates obtaining
//creating certification path (chain to be validated)
CertPath path = cf.generateCertPath(certx);
//validator creation. Algorithm to be defined
CertPathValidator validator = CertPathValidator.getInstance(certPathValidatorAlgorithm);
//get key store
KeyStore keystore = getKeyStore(keyStorePassword);
//get list of CRLs (certificate revoke list)
Collection<? extends CRL> crls = getCrls(cf);
PKIXParameters params = new PKIXParameters(keystore);
CertStore store = CertStore.getInstance(certStoreType, new CollectionCertStoreParameters(crls));
params.addCertStore(store);
//Validate will throw an exception on invalid chains.
PKIXCertPathValidatorResult r = (PKIXCertPathValidatorResult) validator.validate(path, params);
r.getTrustAnchor();
In case of local cacert and CRLs the logic works fine but the CA must be external.
So the getKeyStore() and getCrls() must be customized to access external CA server, establish trusted connection etc. etc.
Could you explain what config and protocols (CMP ?) to be used to support this? Is there something like this in e.g. BouncyCastle?
UPDATE: In fact it's not related to browsers and https at all.
In an XML we get a base64 encoded certificates chain. The certificates were issued by a CA. We need to validate the chain - send it to CA somehow and get Ok/Not Ok response or get a list of CRLs from the CA and provide mechanism to keep valid issued certificates as roots for our chains.
Load a certificate and keys from keystore which is password protected and then use it for cert verification and digital signing
To read the certificate is really trivial.
CertificateFactory factory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) factory.generateCertificate(new FileInputStream("file.pem"));
This is with standard APIs (in try/catch) etc and you have loaded your certificate.
Now the toString method of certificate is not suitable for you since it just captures the "user's" view of the certificate e.g. you would use it for println for instance
Can't you send the certificate object itself?
Not sure what your server expects so you can look into the various methods of certificate
X509Certificate
I use this code
PEMReader pr=new PEMReader(new StringReader(trust_certs));
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
Object o;
int i=0;
while((o=pr.readObject())!=null){
if(o instanceof X509Certificate){
i++;
X509Certificate c=(X509Certificate)o;
trustStore.setCertificateEntry(Integer.toString(i), c);
}
}
http://www.bouncycastle.org/docs/docs1.6/org/bouncycastle/openssl/PEMReader.html
A pem file is read as any other text file. Read the Java tutorial about IO (and concentrate on character streams, since a pem file contains text, and on File IO, since this is what you want to do)
I have an XML document that is digitally signed. I use the XML Digital Signature API to verify the signature. But this document is a SAML 2.0 Assertion that will be used for single sign-on into our web application. As such I need to establish trust in the X.509 certificate used to sign the XML document.
The code I am using to try and establish this trust is:
String filename = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
FileInputStream is = new FileInputStream(filename);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = "changeit";
keystore.load(is, password.toCharArray());
PKIXParameters params = new PKIXParameters(keystore);
params.setRevocationEnabled(false);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
CertPath certPath = certFactory.generateCertPath(Arrays.asList(signatureCertificate));
CertPathValidator certPathValidator = CertPathValidator.getInstance(CertPathValidator.getDefaultType());
CertPathValidatorResult result = certPathValidator.validate(certPath, params);
PKIXCertPathValidatorResult pkixResult = (PKIXCertPathValidatorResult) result;
TrustAnchor ta = pkixResult.getTrustAnchor();
X509Certificate cert = ta.getTrustedCert();
When run the call to certPathValidator.validate() throws a CertPathValidatorException with the message Path does not chain with any of the trust anchors.
Examining the certificate, it says it has been issued by OU=www.verisign.com/CPS Incorp.by Ref. LIABILITY LTD.(c)97 VeriSign,OU=VeriSign International Server CA - Class 3,OU=VeriSign\, Inc.,O=VeriSign Trust Network.
This is not one of the trust anchors in the JDK's cacerts key store.
However, using IE to inspect a similar certificate's trust chain I see that www.verisign.com/CPS Incorp.'s was issued by VeriSign Class 3 Public Primary CA, which does appear to be one of the trust anchors in the JDK's cacerts key store.
My question: how can I get Java to validate this certificate?
Insert the public cert of the issuing CA into the cacert keystore.
edit: You can use keytool or one of the other tools out there. Article describes keytool use: keytool-Key and Certificate Management Tool
Exactly what xelco said - add the intermediate CA:
OU=www.verisign.com/CPS Incorp.by Ref. LIABILITY LTD.(c)97 VeriSign,OU=VeriSign International Server CA - Class 3,OU=VeriSign\, Inc.,O=VeriSign Trust Network
To the JDK's key store. You can use keytool to do it.
Reason: Generally when an XML message is signed, the signature includes only the signing cert. X509 Certificates are like singly linked lists. The End Entity points to its issuer. The issuer points to its issuer until you get to a self-signed Root CA, which points to itself. To verify a certificate according to PKIX, the validator needs to be able to build the whole CA chain from end entity to self signed root, so every part of the chain (except for the end entity) must be in your certificate store.
I've got better solution. I've found java service that can be run and do everything for us.
Java:
http://code.google.com/p/java-use-examples/source/browse/trunk/src/com/aw/ad/util/InstallCert.java