Need to get the CA certificate out of an Active Directory server for use with other systems? I had this need when trying to connect Atlassian Jira to an internal Active Directory domain controller; without the CA certificate, you can’t do LDAPS to the AD server because Jira won’t trust it.
The ldapsearch utility will help you do this. It should be present in the “openldap-clients” package available on most linux distributions in whatever package maintainer they use. It is also present by default in MacOS.
You will need a valid account on the domain in question, but it does not require any particular privileges. Here is the command, followed by an explanation of the arguments, and which ones you’ll need to change:
LDAPTLS_REQCERT=never ldapsearch -W -T ~/Desktop/ -t -x -H "ldaps://DC1.corporate.local:636" -D "CN=USERNAME,OU=LDAP,OU=Staff,dc=corporate,dc=local" -b "cn=configuration,dc=corporate,dc=local" "cacertificate=*"
Code language: JavaScript (javascript)
- LDAPTLS_REQCERT=never – this is run in advance of the command to instruct ldapsearch to trust the cert that comes from the LDAP server. Most AD domains use an internal certificate authority (CA) so the computer where you’re running this command will probably not trust the certificate the server attempts to supply, then ldapsearch errors out. Those errors, if ldapsearch were being used with a -d 1 argument, look like:
TLS: during handshake: peer cert is valid, or was ignored if verification disabled (-9841)
TLS: during handshake: Peer certificate is not trusted: kSecTrustResultRecoverableTrustFailure
tlsst_session_upflags(0x7fc77d40d3a0)
tlsst_session_errmsg(0x7fc77d40d3a0)
TLS: can't connect: SSLHandshake() failed: misc. bad certificate (-9825).
- -W prompts for the password associated with the username supplied in the CN= line
- -T sets the output directory for the files that will be saved
- -t saves the files as binary data
- -x means use user/pass (simple) authentication
- -H supplies the server to talk to as a URI; this is necessary to tell it it’s using ldaps as it will normally try to starttls even if the port is the typical secure port
- -D provides the DN to bind to. This is something which will require customization on a per-user/per-domain basis. You will need to customize both the CN= with your username of choice as well as the OU and dc values to match the Windows AD domain being queried.
- -b the base DN for the search. The dc= portions will need customization to the Windows AD domain being queried.
Okay, you are now ready to execute the customized version of the above command. It will output content similar to the following:
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <cn=configuration,dc=corporate,dc=local> with scope subtree
# filter: cacertificate=*
# requesting: ALL
#
# corporate-DC1-CA, Enrollment Services, Public Key Services, Services, Configuration, corporate.local
dn: CN=corporate-DC1-CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=corporate,DC=local
objectClass: top
objectClass: pKIEnrollmentService
cn: corporate-DC1-CA
cACertificate:< file:///Users/username/Desktop/ldapsearch-cACertificate-XnZABa
distinguishedName: CN=corporate-DC1-CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=corporate,DC=local
instanceType: 4
whenCreated: 20190914182852.0Z
whenChanged: 20191024193801.0Z
displayName: corporate-DC1-CA
....
cACertificateDN: CN=corporate-DC1-CA, DC=corporate, DC=local
Code language: HTML, XML (xml)
There may be quite a few lines like that. So you’ll have to pay attention to the output and look for an instance where the “cn:” line for that particular certificate matches the “cACertificateDN” line of both itself, and the other certs that are output. That’s going to be the domain’s CA certificate and the one you want.
So, now that you’ve found the appropriate block of output, the important part will be the cACertificate line that provides the path to the file that ldapsearch saved:
cACertificate:< file:///Users/username/Desktop/ldapsearch-cACertificate-XnZABa
Code language: JavaScript (javascript)
Since I used ~/Desktop/ on my MacOS system, that’s where it ended up. The file will be in binary DER format. So, now we’ll run the output file through OpenSSL to spit out a PEM-format cert either to console or file:
# openssl x509 -inform der -in ~/Desktop/ldapsearch-cACertificate-XnZABa
-----BEGIN CERTIFICATE-----
.....
-----END CERTIFICATE-----
### OR ###
# openssl x509 -inform der -in ~/Desktop/ldapsearch-cACertificate-XnZABa -text -out ~/Desktop/ldapsearch-cACertificate-XnZABa.pem
Code language: PHP (php)
Now you can import the certificate into whatever application needs to trust the AD server for LDAPS connections. If it’s Jira, like in my case, you’ll of course have to repeat this import every single f’ing upgrade since they use their own bundled JRE with a cacert store that gets replaced at every upgrade. No idea why they can’t store custom certs in the database independent of the app files. If you need those steps, they are:
JAVA_HOME="/opt/atlassian/jira/jre/"
export JAVA_HOME
cd /opt/atlassian/jira/jre/bin/
./keytool -importcert -alias ldapCert -file /root/ldapsearch-cACertificate-XnZABa.pem -keystore $JAVA_HOME/lib/security/cacerts
# The password the above command will need is: changeit
Code language: Bash (bash)