OpenLDAP: TLS error -8179:Peer's Certificate issuer is not recognized - ssl

I'm not familiar with certificates and openldap. I'm trying to port someone elses work from an older OS to CentOS-6 with openldap-2.4.23. On the old OS, an ldap connection worked without issue. Now on CentOS-6, I get the following error when doing a simple bind:
TLS error -8179:Peer's Certificate issuer is not recognized.
My /etc/openldap/ldap.conf has a single line:
TLS_CACERTDIR /etc/openldap/certs
I tried commenting out that line and putting the following into the file but that didn't change the error message I received.
tls_reqcert allow
I also tried putting only the following line in ldap.conf but that didn't change the error. I tried this based on information found in this question.
LDAPTLS_CACERT /etc/ssl/certs/ca-bundle.crt
I copied files into the following directories:
/etc/pki/tls/certs/ca.crt
/etc/pki/tls/certs/server.crt
/etc/pki/tls/private/server.key
I have no choice but to use openldap-2.4.23. Any idea what is causing this error or what I can do to troubleshoot?
Thanks in advance.
SP

As per http://www.zytrax.com/books/ldap/ch6/ldap-conf.html TLS_CACERT should point to the file containing the CA cert that the client will use to verify the certificate. You need to make sure the your servers CA [The CA that signed your server certificate] is present in the file that TLS_CACERT points to[in your case /etc/ssl/certs/ca-bundle.crt.

I had the same error. In my case the reason was, that my client had the wrong certificate in /etc/ipa/ca.crt. To fix this, I just copied /etc/ipa/ca.crt from the KDC server to the client and the error disappeared.

Depending upon the environment, OpenLDAP may completely ignore the value set for TLS_CACERTDIR because evidently GnuTLS doesn't support that type of certificate store.
From the man page for ldap.conf(5)
TLS_CACERTDIR <path>
Specifies the path of a directory that contains Certifiā€
cate Authority certificates in separate individual files.
The TLS_CACERT is always used before TLS_CACERTDIR. This
parameter is ignored with GnuTLS.
In my case, I suspect that GnuTLS is in use, so TLS_CACERTDIR simply does nothing. Using TLS_CACERT pointed to a file containing the certificate of my server's signing CA seems to have done the trick.
I think https://serverfault.com/questions/437546/centos-openldap-cert-trust-issues is a much more complete answer.

Related

Ubuntu Server 16.04 error 60: SSL certificate problem

Ubuntu server 16.04 PHP7.4 Apache2 running wordpress Geotrust SHA256 certificate
I have started getting the following error
cURL error 60: SSL certificate problem: unable to get local issuer certificate
I have read through and tried most solutions on the many questions on here, but to no avail
The latest 2 i have tried is adding to php.ini the following 2 lines and restarted Apache and rebooted after each one to see if it solves the issue. But it does not
After downloading a fresh copy of cacert.pem The first one i tried was
curl.cainfo = "/path/to/cacert.pem"
Then i tried
openssl.cafile = "/path/to/cacert.pem"
But i still get the same error
Any assistance greatly appreciated.
Many thanks
This is likely to be a server problem ("unable to get local issuer certificate" often is):
Even when using a CA bundle to verify a server cert, you might still experience problems if your CA store does not contain the certificates for the intermediates if the server doesn't provide them.
The TLS protocol mandates that the intermediate certificates are sent in the handshake, but as browsers have ways to survive or work around such omissions, missing intermediates in TLS handshakes still happen that browser-users won't notice.
Browsers work around this problem in two ways: they cache intermediate certificates from previous transfers and some implement the TLS "AIA" extension that lets the client explicitly download such cerfificates on demand.
To figure out for sure if this is your problem, use a TLS test service like perhaps this one: https://www.ssllabs.com/ssltest/

Solve boost.asio certificate failed error -without- access to source code, to find out what information Philips Hue Bridge shares

This is a bit of a super duper specific question, but who knows there's someone out there that can help me.
I happen to have Philips Hue Bridge and I would love to know what personal information it is sharing with the outside world. Using tcpdump on my router I figured the Hue Bridge has a rather talkative personality. But because it talks over SSL tunnels, I have no idea what it says. So what I did is I setup a SonicWall with SSL-DPI with a CA, got root access to the Hue Bridge and found the application that does the talking to wws://ws.meethue.com (its called websocketcd). I then replaced the root certificate on the Hue Bridge, adjusted the cipher to match the Sonicwall and now I am stuck due to boost.asio trowing an validation error of my certificate:
error:14090086:lib(20):func(144):reason(134)
For those not too familiar with the error codes, this is what they mean:
lib(20) is ERR_LIB_SSL
func(144) is SSL_F_SSL3_GET_SERVER_CERTIFICATE
reason(134) is SSL_R_CERTIFICATE_VERIFY_FAILED
To verify it's not my SonicWall or certificate that is causing the problem, I executed openssl s_client -connect ws.meethue.com:443 -CAfile ca.pem from the Hue Bridge and that validates the chain perfectly fine, the same way as the original certificate. I also verified that the application is loading my root certificate and cipher correctly (because if change the cipher, I get a cipher error error). Also in my browser, I can visit https://ws.meethue.com without certificate errors. Here's my self made certificate chain, in case someone wants to check it: https://gofile.io/d/5msjoJ (password for download/key 1020304050, it's a temporary key that only exists in my local test env. so it's safe to share ;-)
If websocketcd wasn't a binary file, the problem was super easy to solve using set_verify_mode, but unfortunately it is a binary and that makes life significantly more complicated.
Is there anyone who can give me advice how to make this blob called websocketcd with boost.asio in it accept my root certificate? What I tried too: letting it communicate without ssl and with ssl without encryption (eNULL:aNULL ciphers). I am a bit hesitant to share the blob but for those who have a Hue Bridge too, it's located at /usr/bin/websocketcd.
Perhaps you can use strace (or maybe even ltrace) to spot which certificate paths it is using for root authorities.
If it uses a single file, you might be abel to hack it by replacing it with a CA that verifies your MITM certificate.
Sometimes the file can contain multiple certificates, so worth appending/prepending yours.
If you're in luck, there will be a readdir on a directory containing certificates. If so, you should be able to add your root certificate (in PEM form) there and **remember to run c_rehash on that directory.
For those interested: after some 20hrs, I figured that websocketcd requires a certificate revocation list for each CA in the chain (which do not have to have any revoked serials). These CLRs need to be included in the root CA file that is loaded using the ca-filename argument. I was not aware that Boost Asio could demand that a CLR is present for each CA, but apparently, they (Signify) managed to do so.

Installing certificate for a specific CA, or understanding why the existing one doesn't work

I have the following code in Python3.7:
import urllib.request
import urllib.error
import ssl
import certifi
# Create the SSL context
# Was using cafile=certifi.where() before, but copied it inline. Read below
context = ssl.create_default_context(cafile='cacert.pem')
# Prepare the request
request = urllib.request.Request(some_url)
try:
connection = urllib.request.urlopen(request, context=context)
except urllib.error.URLError as e:
print(e)
I've tried several different some_url and I'm getting a problem for a specific one, https://hypelabs.io. Other URLs are working; I tested, for example, https://facebook.com, https://stackoverflow.com, and so on, all working properly. For hypelabs.io I get this instead:
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1051)>
First thoughts were that the CA was not recognized by the system, and that I needed to install the CA certificate first. I checked the chain in the browser and this is what I found:
However, the COMODO RSA Certification Authority is in all bundle files that I tried (as expected) and in the Keychain as well (I'm using MacOS High Sierra). Notice that the serial numbers match.
The second certificate in the chain is not in the system. I know that the root is enough, but just in case I tried downloading it and adding it to the bundle file, after converting the CRT file to PEM:
Same result. Why is this particular certificate failing? What should I be looking at?
The site is misconfigured and fails to provide a necessary intermediate certificate. The SSLLabs report therefore says:
This server's certificate chain is incomplete. Grade capped to B.
The second certificate in the chain is not in the system. I know that the root is enough, but just in case I tried downloading it and adding it to the bundle file, after converting the CRT file to PEM.
My guess is that you did something wrong here. Given that your description is correct I assume that it does not fully match what you actually did.
I've took the missing certificate with the same fingerprint as can be found here and added it to the list of root CA (taken on Ubuntu from /etc/ssl/certs/ca-certificates.crt. After that access to the site worked without any problems.

How to tell LDAP SSL server with multiple certificates to return the one that I need?

My simple LDAP java program, using
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, <UserDN>);
env.put(Context.SECURITY_CREDENTIALS, <Password>);
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put(Context.PROVIDER_URL, "ldaps://<host>:636");
to make LDAP SSL authentication stopped working ever since a 2nd server certificate with the same CN but other details in the subject are different was installed on the server which I don't have access at all.
The program fails when I make the initial context
new InitialDirContext(env);
The error is "Failed to initialize directory context: <host>:636"
It returns the 2nd server certificate when I run
openssl s_client -showcerts -connect <host>:636 </dev/null
that makes me believe that the solution will be to find a way to tell the server which certificate to use.
I search and read a lot of articles on this topic and I have to admit that I am very confused, it is not clear to me if these articles are talking about client certificate or server certificate, or the actions to be taken are for the client side, or server side.
In one article, it says that I can use a custom SSLSocketFactory with the keystore path and
env.put("java.naming.ldap.factory.socket", "com.xxx.MyCustomSSLSocketFactory");
But I don't know the path to the server certificate keystore on the server.
In one Microsoft article, it says the best resolution is to have just one server certificate on the server or to put the server certificate to Active Directory Domain Services (NTDS\Personal) certificate store for LDAPS communications. But I don't have access to the server and the 'fix' to this problem has to be done in my LDAP java program.
In another article, it says to use Server Name Indication (SNI) extension.
So is there a way that I can specify which certificate I want to the server? Or my problem is somewhere else?
Thanks a lot.
Here is the stack trace:
javax.naming.ServiceUnavailableException: <host>:636; socket closed
at com.sun.jndi.ldap.Connection.readReply(Connection.java:419)
at com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:340)
at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:192)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2694)
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:293)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.InitialContext.<init>(InitialContext.java:197)
at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:82)
When I used Jxplorer to run the same test, it gave me the same error.
EJP was right to point out that the issue was that the certificate was not trusted. Many thanks EJP.
When I installed the CA Certificate in %JAVA_HOME%/lib/security/cacerts, Jxplorer worked. My program still failed. I had to add these lines in it to make it work (not sure if I need all of them though ...):
System.setProperty("javax.net.ssl.keyStore",%JAVA_HOME%/lib/security/cacerts);
System.setProperty("javax.net.ssl.trustStore",%JAVA_HOME%/lib/security/cacerts);
System.setProperty("javax.net.ssl.keyStorePassword=changeit);
System.setProperty("javax.net.ssl.trustStorePassword=changeit);
But since the certificate is not trusted in the first place, I simply 'force' our server to trust it, hence this solution is not acceptable. And neither our server nor the LDAP server runs with Java 7. So SNI is out too!
EJP mentioned that I could control the server certificate by restricting the cipher suites or accepted issuers in the client (my webapp), if the server certificates have different algorithms or issuers. The 2 certificates do have different issuers, however, I don't know how to do that and I could not find anything on that neither.
EJP can you please elaborate, or point me to some sites ... ?
If the certificates have different issuers, you can control which certificate you get at the client by controlling which of those issuers is in your truststore. If only one of them is, that's the one you'll get. If they're both there, you get pot luck. Note that if your truststore also contains a common super-issuer, again it's probably pot luck.
The result isn't pot luck if you specify one and only one certificate in the Certificates - Service (Active Directory Domain Service) - NTDS\Personal location in Microsoft Management Console. Contrary to Microsoft docs I've read, though, a domain controller restart seemed to be necessary for the newly specified certificate to 'take hold'.

SSL client authentication returning Bad Certificate error

I was trying to connect to my custom wrote ssl server written in CPP. It has got client authentication features. Its throwing error Bad certificate when watched through Wireshark. At the server side the error returned was
14560:error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned:s3_srvr.c:2619:
I used the following code to force requesting client certificate
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_verify_depth(ctx, 1);
I could see client returning certificate in Wireshark.
Which function should be used to set the public key used for verifying the client certificate at the server side?
From the error messages it looks like your client does not present a certificate to server and you explicitely requested that a client needs to present one (in server code):
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
What you probably need is to tell your client code to use certificate (along with a private key):
SSL_CTX_use_certificate_chain_file(ctx, pcszCertPath);
SSL_CTX_use_PrivateKey_file(ctx, pcszPrivKeyPath,SSL_FILETYPE_PEM);
I hope that helps.
Also make sure that your server uses the same certificate chain (that it trusts the same CA's). If this is a problem, let me know and I'll help you do that.
With wireshark, you will find out if the server ever requested certificate from the client. The command would be "CertificateRequest".
I was getting a similar error (only line number different):
140671281543104:error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned:s3_srvr.c:3292:
I had generated self-signed certificates using the procedure mentioned in https://help.ubuntu.com/community/OpenSSL.
After juggling with the error for one day, i found that the error was because the self-generated CA was not in the trust chain of the machine I was using.
To add the CA to the trust chain in RHEL-7, one can follow the below procedure:
To add a certificate in the simple PEM or DER file formats to the
list of CAs trusted on the system:
Copy it to the
/etc/pki/ca-trust/source/anchors/
subdirectory, and run the
update-ca-trust
command.
If your certificate is in the extended BEGIN TRUSTED file format,
then place it into the main source/ directory instead.
I think the above procedure can be followed for fedora too.
If "update-ca-trust" command is not available, it might be useful to explore the commands like "update-ca-certificates".
Hope this will be useful to someone.
Difference Between SSLCACertificateFile and SSLCertificateChainFile
SSLCertificateChainFile is generally the correct option to choose, as it has the least impact; it causes the listed file to be sent along with the certificate to any clients that connect.
Provide all the Root CA into the following file to resolve the issue
SSLCACertificateFile (hereafter "CACert") does everything SSLCertificateChainFile does (hereafter "Chain"), and additionally permits the use of the cert in question to sign client certificates. This sort of authentication is quite rare (at least for the moment), and if you aren't using it, there's IMHO no reason to augment its functionality by using CACert instead of Chain. On the flipside, one could argue that there's no harm in the additional functionality, and CACert covers all cases. Both arguments are valid.
Needless to say, if you ask the cert vendor, they'll always push for CACert over Chain, since it gives them another thing (client certs) that they can potentially sell you down the line. ;)
Modify the server code with the below line:
Server code:
SSL_CTX_load_verify_locations(ctx,"client_certificate_ca.pem", NULL);
Here client_certificate_ca.pem is the file which generated the client certificates.
verify your client certificate with the "client_certificate_ca.pem" file using below command.
verify -CAfile client_certificate_ca.pem client_certificate.pem
Client code:
if (SSL_CTX_use_certificate_file(ctx, "client_certificate.pem", SSL_FILETYPE_PEM) <= 0)
{
}
if (SSL_CTX_use_PrivateKey_file(ctx, "client_certificate.ky", SSL_FILETYPE_PEM) <= 0)
{
}
if (!SSL_CTX_check_private_key(ctx))
{
}