Renew SSL root CA cert - client programs in the wild need update? - ssl

Here is my situation:
I have a client application that I'm going to distribute - we'll call it MyClient.
MyClient does some SSL communication with one of our servers.
MyClient has the root CA embedded in it, so it can do proper verification of the server certificate.
Now, suppose some years go by, the root CA expires, and is renewed.
Does that mean I need to patch MyClient in the wild?
In other words, will a change to the validity dates on the certificate cause it to no longer match the baked-in root CA in MyClient?
Addendum: Suppose I write my client to not validate the date of the cert (but everything else). Then, when the root CA expires and is re-issued, do I still need to patch? Will other parts that play into the validation change, other than the date?

If your client is ensuring an SSL server certificate is issued by a particular root CA and that root CA is included in the client then yes, you will need to patch your client to replace the root CA certificate.
There are few good ways of doing this. What tends to happen is that root CA certificates are very long lived and use shorter lived intermediate CAs to issue SSL certificates but it sounds like this is not the case here.
Looking on the bright side, I do not know what algorithms were used with the old root CA certificate but, hopefully, The new root CA certificate will hopefully use a larger key (2048-bit RSA rather than 1024-bit or 512-bit) and a better hashing algorithm (SHA1 or better rather than MD5) so it may be a good opportunity to increase security.

Related

Why does SSLLabs say my certificate is fine when my CA's cert is expired?

I did a scan of my domain using ssllabs.com, and this is what it says:
From what I can tell, one of my CAs is USERTrust RSA Certification Authority, and their certificate is expired, which SSLLabs flagged red, but it still says that there are no chain issues, and no browsers complain about talking to my domain.
I did the check after curl was complaining about an expired cert when talking to my domain, which may or may not be related.
What's going on here? How can an expired CA certificate not be a problem?
The expired certificate is actually not used for validation. It is unnecessarily send by your server, i.e. you could remove it from the certificate chain you send since modern system have a trusted CA builtin which effectively replaces this expired intermediate CA. For more details see for example USERTrust Intermediate Expiration in 2020. To cite:
This is an old intermediate certificate and modern operating systems have a new version available and won't be affected. ... Based on what we know, equipment released or receiving security updates after June 2010 will most likely not be affected. ...

SSL TrustStore without CA, only client certificate

I have a custom CAroot.crt (generated by me) and all my clients certificates are signed with this CAroot.crt. I have a TrustStore.jks where I put only clients certificates and not CAroot.crt, because I would like to have the possibility to remove a client from my truststore any time.
When I try to start my application I got the following:
*** Certificate chain
<Empty>
***
main, fatal error: 42: null cert chain
This is my trustStore.jks:
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry
Alias name: localhost
Creation date: Nov 23, 2019
Entry type: trustedCertEntry
Owner: CN=localhost, OU=IT, O=QUEROBUY, L=SAO CAETANO DO SUL, ST=SAO PAULO, C=BR
Issuer: CN=localhost, OU=IT, O=LANHELLAS XYZ, L=SAO CAETANO DO SUL, ST=SAO PAULO, C=BR
Serial number: 5416c04e360f9d50323c52d8a5b04be2969c9b86
Valid from: Sat Nov 23 16:39:54 BRT 2019 until: Tue Apr 06 16:39:54 BRT 2021
Certificate fingerprints:
MD5: 8F:29:1C:1F:05:89:0B:E6:A0:57:84:FE:B0:78:68:2D
SHA1: 95:C8:EA:0E:C8:7C:4E:99:E4:73:85:49:57:D6:BB:88:AF:52:52:12
SHA256: 7E:ED:19:AF:02:DB:CC:88:98:D0:10:4E:39:67:AA:4D:3F:70:DA:76:03:1B:CB:41:06:DC:3B:51:38:16:78:5F
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 1
*******************************************
*******************************************
If I add "CARoot.crt" to my trustStore.jks everything works fine, but I lose the chance to invalidate some specific client certificate. Imagine, I have 10 clients, each one with your own certificate (.crt) assigned by "CARoot.crt" but Client 001 for some reason should be invalidated immediately, I will just remove your public key from trustStore.jks in server, without that I should wait for certificate expiration date.
WHY: if you look slightly earlier in the debuglog you will see the CertificateRequest message, which specifies (among other things) the Cert[ificate] Authorities the server asks for; see rfc5246. Java defines this as the Subject names of the certs in the truststore, because the certs in the truststore are normally expected to be CA certs (and usually CA root certs, as the predefined ones are). Most client software obeys this instruction, though there are exceptions. Thus if your truststore contains certs like
Subject=Client1 Issuer=MyCA
Subject=Client2 Issuer=MyCA
Subject=Client3 Issuer=MyCA
then your server will ask for certs issued by any of Client1 Client2 Client3 but not MyCA. If the client actually has only one cert and it is for e.g. Client2 but is issued by MyCA -- not by any Clientn -- most client software will consider that cert unacceptable for this server/handshake.
THE PKI WAY. It is not true that a certificate can't be invalidated before expiration. PKI in general is explicitly designed to deal with such cases, which are generically termed revocation. There are various reasons a certificate can be revoked before expiring; for the particular PKI scheme used for SSL/TLS (and by Java for other things as well, like code signing), namely PKIX (or the effectively equivalent X.509) see rfc5280 5.3.1 as well as the rest of section 5 for Certificate Revocation Lists (CRLs), the older and traditional way of handling revocation, and rfc6960 for Online Certificate Status Protocol (OCSP), the newer way.
For the 'real' (public) PKI this mostly just works. Java implements PKIX revocation checking, but for SSL/TLS (JSSE) it is disabled by default; you must set sysprop com.sun.net.ssl.checkRevocation to use it. You may also need to set com.sun.security.enableCRLDP for CRLs and AFAICT always need to set security property (not sysprop) ocsp.enable for OCSP. See e.g.:
Check X509 certificate revocation status in Spring-Security before authenticating
Checking a X509 Certificate Revocation
Java SSL Certificate Revocation Checking
But running CRL distribution point(s) and/or OCSP responder(s) so that they are correct and available when needed -- which can be any time -- is non-trivial; this is one of the things real CAs charge money for (or get subsidized). Doing this for your own personal CA can vary from a pain in the butt to effectively impossible, but if you want to, be much more specific about your CA.
Your situation is in principle simpler; you have only one CA and you operate it, so you know when revocations occur. You could trivially provide the CRL(s) to the server when it(they) change. But AFAICS the builtin code has no way to use that information, so you'll have to use the hook that allows writing your own TrustManager in place of the builtin one, and modify it to use a validator with a CertStore that uses the CRLs. This is probably also a fair bit of work, but only once.
WORKAROUNDS. Instead of doing it 'right' in PKI terms, you could continue with your approach of trusting the leaf certs individually by modifying the server or the clients.
You could change the (X509)TrustManager hook in the server to validate certs as usual, but override getAcceptedIssuers to return a different (and correct for your case) list of 'requested' CAs, causing JSSE to send a CertificateRequest that causes the client(s) to use their correct cert(s).
Depending on the clients you might be able to change them to ignore the 'requested' CAs and send their cert anyway -- which the server's default TrustManager will validate if it is in the truststore (or the CA is). For OpenSSL this is easy; OpenSSL already ignores the requested CA list and just sends whatever is configured. For Java you could hook the client KeyManager and override chooseClientAliases method to not check against the list of desired issuers as it normally does. For other clients add to your Q or ask a new one.
TrustStore.jks is how java will determine whether or not it trusts a certificate. Its essentially a keystore file of root certificates. You will have to add your root certificate to this store if you want to avoid "not trustes messages."
In your scenario, since you used that root to issue 10 client certificates, removing the client_certificate.crt from your trust or key stores wont distrust it. Because, by design, java is looking at the TrustStore and finding the root certificate and thus trusting client_certificate.crt still. You are going to need a redesign of your CA.
When deploying any sort of PKI infrastructure, you will need to also set up CRL and/or OCSP servers. These are the two protocols used to revoke a certificate.
I also recommend you do not issue "end user certificates" directly from the root. Its best issue intermediate certificates off the root, and then use intermediate_certificate.crt to issue your actual server or client certs.
For a reason why, see here: https://security.stackexchange.com/questions/128779/why-is-it-more-secure-to-use-intermediate-ca-certificates#128800
And here is a great and easy way to deploy your own CA using OpenSSL. It will show you how to set up the root, intermediate, and revocation servers. https://jamielinux.com/docs/openssl-certificate-authority/

In SSL trust hierarchies, what is used to sign an intermediate certificate and how does this relate to the root certificate?

I'm completing an assignment on SSL and I feel I understand the basics of how certs are used with asymmetric and symmetric encryption. But I'm having difficulty understanding some details of how exactly trust hierarchies work.
Specifically, what is used to sign an intermediate certificate? All the guides I've looked at state that the CA root cert is used to sign the intermediate cert. But what exactly does "sign" mean here? In other words, how does a server prove that its intermediate certificate is authenticated by the CA root cert?
My guess is that the public key or signature of the root cert are used when generating the signature of intermediate cert the but I'm not sure if this is accurate.
I would really appreciate any info to improve my understanding.
If there is exactly one intermediate, which is often but not always the case, the intermediate cert is signed by the root in exactly the same way an end-entity cert (for SSL/TLS mostly a server cert) is signed by the intermediate. In both cases this is a shorthand; signing is actually done using the private key of an asymmetric keypair, and the cert contains the public key of the same keypair which is used to verify signatures made with the private key. Since the private keys are private and all of us who use the CAs see only their public keys, we focus on that. Thus:
the server cert is signed using the private key belonging to the intermediate CA; the intermediate cert contains the matching public key. As part of verifying the server cert, the relier (e.g. browser) finds or confirms the intermediate cert using the Isssuer name in the server cert, and uses the public key from the intermediate cert to verify the signature on the server cert; this assures that the server cert was actually issued by the intermediate CA and has not been tampered with.
According to SSL/TLS standards the server should always send the intermediate cert (or certs, in order) following the server cert in the handshake, although if it fails to do so, some clients may use AIA from the certificate or other heuristic means to obtain the cert, or may have it already cached or even configured.
the intermediate cert is signed using the private key belonging to the root CA; the root cert contains the matching public key. As part of verifying the intermediate cert, the relier finds the root cert using the Issuer name in the intermediate cert, and uses the public key from the root cert to verify the signature on the intermediate cert; this assures that the intermediate cert was actually issued by the root CA and has not been tampered with.
The root cert normally must (already) be in the relier's local 'trust store' and the server does not need to send it; normally the trust store is provided either by the browser developer (Firefox) or by the OS/platform developer (IE/Edge, Chrome, Safari).
Notice the close parallel between these two statements with the (notable) exception of how the relier finds the parent cert. Also note that validating a server cert chain for an SSL/TLS connection involves much more than just verifying the signatures, although verifying the signatures is a critical part and without it the other validation criteria could not be assured.
One intermediate CA, and intermediate cert, will generally be used by a large number (thousands to millions) of server certs and servers. The server isn't responsible for 'proving' anything about the intermediate cert, only passing it on to the client, which validates the entire chain.
Cross-stack see also
https://security.stackexchange.com/questions/56389/ssl-certificate-framework-101-how-does-the-browser-actually-verify-the-validity
which has a nice graphic of this relationship.

2 Way SSL using Apache - Certificate questions

I've been googling like mad trying to figure this out, but the answer doesn't seem to be clear, or at least, it seems like there are contradictory answers.
I'm tasked with setting up an Apache web server with 2Way SSL authentication. We use verisign to get our certificates, so we have a certificate for the web instance with the correct hostname details, signed by verisign, and an intermediate certificate from verisign. This all works very well.
Now, we need to set up a 2Way SSL connection. The initial expectation is that the client will manage their own certificates, and provide them to us for authentication. More than one client may be connecting, and they should each have access to different resources when they connect.
From what I've read, I'm not sure how this would be done...
This is a pretty good overview, but in this situation, they are using self-signed certificates: https://security.stackexchange.com/questions/34897/configure-ssl-mutual-two-way-authentication
Using these details, it would seem like we would have to make the trusted CA point to the certificate authority that signs the client's certificate.
Is it possible to use the client certificate as the trusted CA (even though it isn't self signed, but signed by a CA) or would we have to put a trusted CA from their signer (and at that point, would a CA bundle that includes all the client certificate authority CAs work?) on the server and then use the SSLRequire statements to limit access to specific details of the certificate?
As a followup, can we use the SSL Certificate that we get from verisign to sign client certificates?
So, after several more hours on google, and some testing, I was able to figure out what I needed to.
If I want to use a certificate signed by verisign or some other public CA, I would have to copy their public intermediate certificate (the one that they use to sign the client certs) to my server and specify it as the SSLCACertificateFile in the configuration. The caveat is that then any cert signed by that CA would be accepted, and that's where the SSLRequire directives can used to narrow that down to specific certificates.
Using the SSLVerifyClient optional_no_ca directive would make it assume that the cert is trusted, even if it isn't, and then I would have to use SSLRequire directives to verify the details are correct, however, anybody could create and sign their own certificate with those details and there would be no way to tell.
Creating my own self signed CA certificate, and then using that to sign the client certificates and issuing them to the clients is the only way to both ensure that the cert isn't a forgery and not requiring SSLRequire directives to ensure that only the people that I specify can connect.
Please comment/correct me if I'm wrong on any of this.
Use:
SSLVerifyClient optional_no_ca
In your Apache config. This will request the client certificate but not validate it against a CA. It will then be up to your local script to examine the resulting environment variables set by Apache such as 'SSL_SERVER_S_DN' and decide whether to allow the request or not.
These mod_ssl environment variables are also what your code needs to look at when determining what resources the client can access.
The full documentation is here mod_ssl although you probably found that already.
A note on client certificates. If you did want to use a CA and leave it to the clients, they may all use different CA's and you would have a job maintaining them all on your server. It would be much better to trust a single CA.
The advantage would be that then you could use the build in SSL support to do all your certificate checks and not write your own solution.
You could enforce a single CA by specifying an on-line provider and using email signing certificates to identify clients. These would work fine, just the Certificate Subject would be an email address instead of a domain name.
Or you could set up your own CA and sign client certificates yourself. This is not too difficult and gives you complete control. Either route would require you to add the CA root certificate (plus intermediates) to a file Apache can read and point 'SSLCACertificateFile' to it.

Is it possible to prevent man-in-the-middle attack when using self-signed certificates?

I'm not sure is similar question has been asked before (I couldn't find any), but is it possible to protect Client/Server from Man-In-The-Middle attack?
I'm writing a Client application to communicate with Server. Communication will be SSLv3 based.
I am OK with server's self-signed certificates, but worried about someone else generating same self-signed certificate in the same server name and pretend to be it. My Client application uses OpenSSL library. [Client and Server are thrift based, if it makes any difference]. Can I avoid such attack at the same time maintaining support for self-signed certificates?
Yes.
In short, a self signed certificate is more insecure than a CA certificate only when the client does not know the certificate in advance and therefore has no way to validate that the server is who it says it is.
If you add the self signed certificate to the client and don't accept any other certificate, you're actually as secure (or, one could argue, even more so) than having a certificate authority signed certificate.
The important parts to keep SSL secure with or without a certificate authority are;
The server private key (and in the case of a CA, the private keys of all its roots) is kept secret.
The client knows the server certificate (or its CA root).
You can hard-code the server's certificate and compare it against what you receive.
Or better yet, create a CA certificate and server certificate, signed by the CA. Have the CA trusted on the client (again by hardcoding it in your application) and validate received server certificate using the CA certificate.
If you can protect your private keys well enough, a middleman will not be able to masquerade as you, assuming the user actually looks at the certificate. The problem with self-signed is that if you want the user to add the exception to their browser, or just ignore the warning, then you are exposed to man-in-the-middle attack, because anyone else may create their own certificate.
Of course, "protecting your private keys well enough" is not trivial at all. When you pay for a "Verisign" certificate, you're not paying for their software creating the certificate - you're paying for the security forces they have guarding the building in which the private keys are stored.
That's easy! NOOOO !!! Not anymore than you could prevent a man-in-the-middle attack from certificate issued-by a well-know authority. >:)