SAML 2.0 - How to verify the sender certificate? - java

I implement a SAML SP in Java.
I send an AuthnRequest to SAML 2.0 IDP and gets an encrypted response.
My question is:
How do I make sure that the response indeed comes from the IDP and not from a hacker?
It is not enough to validate the signature, since this only tells me that the sender has a matching pair of private/public keys, but it could be anyone.
So, I need the IDP to supply me in advance a certificate which I upload to a jks file, and compare it each time to the certificate I extract from the ds:X509Certificate element of the response.
Now, is there a standard way of comparing the sender's certificates with the one stored in my keystore?
I saw the following code:
KeyStore keyStore = getKS();
PKIXParameters params = new PKIXParameters(keyStore);
params.setRevocationEnabled(false);
CertPath certPath = certificateFactory.generateCertPath(Arrays.asList(certFromResponse));
CertPathValidator certPathValidator = CertPathValidator.getInstance(CertPathValidator.getDefaultType());
CertPathValidatorResult result = certPathValidator.validate(certPath, params);
Is it enough? If the validation doesn't throw an exception it verifies the sender's identity?

This is the way i have solved the verification of signatures with OpenSAML
https://blog.samlsecurity.com/2012/11/verifying-signatures-with-opensaml.html
I have also written a book, A Guide to OpenSAML, where I explain in detail encryption and signing and more using OpenSAML.
What is important with the OpenSAML verification methods is that they only verify the cryptographic validity of the signature (That the content has not been changed). It does not however verify that the sender is someone that you trust.
The Signature validator is instantiated with the public key of the sender to validate against, the public key of the sender. This is normally exchanged is the setup of an identity federation using SAML Metadata

Related

Spring Boot - Reading x509 client certificate from HTTP request

How to receive a x509 certificate from client? I'm using Java's Spring-Boot-Framework with embedded tomcat. For protyping I configured this with Java SE:
HttpsExchange httpsExchange = (HttpsExchange) httpReq;
name = httpsExchange.getSSLSession().getPeerPrincipal().getName();
A user gave me a reference to do this here (down below)
#RequestMapping(value = "/grab")
public void grabCert(HttpServletRequest servletRequest) {
Certificate[] certs =
(Certificate[]) servletRequest.getAttribute("javax.servlet.request.X509Certificate");
}
But I'm not able to get some certificate! Maybe because I'm using tomcat, and it is handling all SSL-Connections. So that no certificate is receiving my application. What I have to do, to get the clients certificate? The client certificate is used to get https connection. I need some information from the subject of the certificate. Thanks.
You have to get it from the HttpServletRequest.
You can check the answer to this question: How to get the certificate into the X509 filter (Spring Security)?:
No you can't get it that way. You need to grab it from the HttpServletRequest:
X509Certificate[] certs = (X509Certificate[])HttpServletRequest.getAttribute("javax.servlet.request.X509Certificate");
This was the post I was trying to point you to, written by Gandalf.
And this was the original question

Process for verifying X509 Certificate V3

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.

Getting public key from digital signature

I am working on a java based licensing project. I have a digital certificate file and the data for which the signature was generated. Is there some API or means to get the public key from these information? Basically Public Key from the data and digital certificate information.
If you digital signature is of format PKCS#7 - not detached, then there is a possibility that the sender would have included the certificate as a part of the digital signature.
You will be required to parse the signature to get the certificate.
The Bouncy Castle API has a SignedData class which has a method for getting certificate(s).
Your question is very vague IMHO.
I have a digital certificate file and
the data for which the signature was
generated
If the certificate file has the public key used to verify the signature then you can load it using standard java apis (assuming X509 Certificates).
FileInputStream fin = new FileInputStream("PathToCertificate");
CertificateFactory f = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate)f.generateCertificate(fin);
PublicKey pk = certificate.getPublicKey();
Once you have the public key you can use it to verify the signature.
Is this what you want?
The certificate must bear a reference to the id of the key used to certify your data. From this key, should be able to contact the corresponding certificate authority and obtain the public key by providing its id. It may be available from a public repository too.
The id of the certificate authority should also appear on this certificate.
There are APIs available for sure, but the question is, which framework are you using for digital signatures? Do you have its name? Do you know the certificate type?

How to read issuer String from user's public key?

I want to read issuer String from user's public key with Bouncy Castle. Is there example code or something from which I can learn?
If you can obtain the certificate object, then you can do the following:
((X509Certificate) certificate).getIssuerX500Principal().getName();
The public key itself does not have an issuer - only a certificate has. And you can get the public key from the certificate, but not vice-versa.
Update: Since it appears that you want to verify the validity of your users, the public key alone does not provide this info. Public keys are used for encryption / digital signature verification, but for the rest of PKI you need the certificate. Actually, verifying the issuer that is written in the certificate gives you no guarantee whatsoever. You need to check:
the certificate revocation lists - i.e. whether the certificate is not revoked. This is done either via the provided CRLs or via the ocsp protocol.
the expiration of the certificate
The public key object doesn't say who generated it. It just contains what you need to encrypt (or verify) with the public key.
If you got the public key from a certificate (java.security.cert.X509Certificate), then you can get the certificate issuer from that by using getIssuerX500Principal().
The certificate is a binding of an identity to a public key. As part of that, the certificate indicates who it was issued by. So you can verify whether you trust that issuer and, therefore, the binding.
Also, the key pair very likely wasn't generated by the certificate issuer. The subject just proved to the issuer that it did possess the associated private key.

X.509 Certificate validation with Java and Bouncycastle

through the bouncycastle wiki page I was able to understand how to create a X.509 root certificate and a certification request, but I do not quite understand how to proceed concept- and programming wise after that.
Lets assume party A does a cert request and gets his client certificate from the CA. How can some party B validate A's certificate? What kind of certificate does A need? A root certificate? A 'normal' client certificate?
And how does the validation work on programming level, if we assume that A has successfully send his certificate in DER or PEM format to B?
Any help is much appreciated.
Best Regards,
Rob
From a programmer's perspective, you need a few things to validate an X.509 certificate.
A set of "trust anchors"—the root certificates of CAs that you rely on. These should be protected from tampering, so that an attacker doesn't replace a CA certificate with his own fake. The public keys in these certificates are used to verify the digital signatures on other certificates.
A collection of Intermediate certificates. The application might keep a collection of these, but most protocols, like SSL and S/MIME, that use certificates have a standard way to provide extra certificates. Storing these doesn't require any special care; their integrity is protected by the signature of a root CA.
Revocation information. Even if a certificate was issued by a CA, it might have been revoked prematurely because the private key was disclosed, or the end entity changed their identity. (For example, a person switches jobs and a certificate with their old company's name in it is revoked.) CRLs or a web-service like OCSP can be used to get an update about the status of a certificate.
With these inputs available, you can use the built-in PKIX support to construct and validate a certificate path.
/* Givens. */
InputStream trustStoreInput = ...
char[] password = ...
List<X509Certificate> chain = ...
Collection<X509CRL> crls = ...
/* Construct a valid path. */
KeyStore anchors = KeyStore.getInstance(KeyStore.getDefaultType());
anchors.load(trustStoreInput, password);
X509CertSelector target = new X509CertSelector();
target.setCertificate(chain.get(0));
PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, target);
CertStoreParameters intermediates = new CollectionCertStoreParameters(chain)
params.addCertStore(CertStore.getInstance("Collection", intermediates));
CertStoreParameters revoked = new CollectionCertStoreParameters(crls);
params.addCertStore(CertStore.getInstance("Collection", revoked));
CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
/*
* If build() returns successfully, the certificate is valid. More details
* about the valid path can be obtained through the PKIXBuilderResult.
* If no valid path can be found, a CertPathBuilderException is thrown.
*/
PKIXBuilderResult r = (PKIXBuilderResult) builder.build(params);
An important thing to note is that if a path cannot be found, you don't get much information about the reason. This can be frustrating, but it is that way by design. In general, there are many potential paths. If they all fail for different reasons, how would the path builder decide what to report as the reason?
Ok, the idea behind CAs is as follows:
CAs are people everyone trusts. To this end, a selection of Trusted CAs is available in your browser/email client/even on my mobile. In your case, your public root key (certificate) should be in your application.
Users send requests to the CA for a certificate in PEM format with the public key. CAs do some (I leave this ambiguous deliberately) form of verification of the end user, such as charging them money or in the case of enhanced verification (green) certs, background checks.
If the CA doesn't think the user's request is valid, they communicate this somehow.
If they do, they sign the public key and produce a certificate containing this information. This is where you process the cert-req and turn it into an X.509 cert.
Other users come across our fictitious user and want to know if they can trust them. So, they take a look at the certificate and find it is digitally signed by someone they have in their trust list. So, the fact that they trust the root CA and only the root CA could sign (via their private key) this user's public key and the CA trusts the user, we deduce that the new user can trust mr fictitious.
On a programmatic level, you implement this by reading the X.509 certificate and working out who the CA is supposed to be. Given that CA's fingerprint, you find it in your database and verify the signature. If it matches, you have your chain of trust.
This works because, as I've said, only the CA can create the digital signature but anyone can verify it. It is exactly the reverse of the encryption concept. What you do is "encrypt with the private key" the data you wish to sign and verify that the "decrypt with the public key" equals the data you've got.

Categories