Mac OS X Server, as of Tiger, has a spiffy little UI in the Server Admin tool for creating SSL certificate requests, importing certs, or creating self-signed certs. It’s pretty easy to make it all work for http or LDAP using the GUI tools.
There is also the command-line ‘serveradmin’ tool, which attempts to mirror the functionality of the Server Admin GUI tool. I was preparing procedures to enable SSL for some Open Directory servers, so I was banging through the various alternatives to see which one is best, when I came upon an interesting scenario.
It seems that when using the command-line ‘serveradmin’ tool to enable SSL, it would only work sometimes. On a test machine, configured as an OD server, I created a valid self-signed SSL cert, then used ‘serveradmin’ to make the appropriate settings, as suggested in the man page. I created a file that contains the settings I want, then load it into serveradmin. I named the file ssl_config, and the contents are:
dirserv:LDAPSettings:LDAPSSLKeyPath = "/etc/certificates/dirt.apple.com.key"
dirserv:LDAPSettings:LDAPSSLCertificatePath = "/etc/certificates/dirt.apple.com.crt"
dirserv:LDAPSettings:useSSL = yes
This configuration can then be loaded by executing:
sudo serveradmin settings < ssl_config
If it worked, serveradmin will echo the new settings when they are applied. After doing this, servermgr knows that slapd has to be restarted, and does so. In my case, slapd would only sometimes reload successfully. Other times, the slapd startup would fail with the following (which you could see by starting slapd in debug mode; sudo /usr/libexec/slapd -d 99 -f /etc/openldap/slapd.conf)
TLS: could not use key file `/etc/certificates/dirt.apple.com.key'.
TLS: error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long asn1_lib.c:140
main: TLS init def ctx failed: -1
... yet when I would revert the SSL configuration back to default, and use the GUI Server Admin to select the same certificate, it would work! What the crap?!? Furthermore, why did it only fail *sometimes*?
Turns out that the failure cases were all ones in which I had supplied a password for the SSL private key, which creates an encrypted private key file. In order to use this key, the password must be supplied to decrypt it before it can be loaded.
Apple does this for apache using an Apple tool located at /etc/httpd/getsslpassphrase. Based on my admitedly layman's understanding of a string dump of this tool, it appears to look for the SSL key password in /etc/httpd/servermgr_web_httpd_config.plist so that apache can use it to unlock the key and start the service.
But we're not talking Apache, we're talking OpenLDAP. Without configuring any Apache vhosts for SSL, that file doesn't contain the private key password, and yet slapd is still able to start successfully.
Digging deeper, if we look at the /etc/openldap/slapd_macosxserver.conf config file after a successful SSL configuration (e.g. using Server Admin), we see:
# This file should NOT be world readable.
# This file is maintained by Server Admin.
...
TLSCertificateFile /etc/certificates/dirt.apple.com.crt
TLSCertificateKeyFile /etc/certificates/dirt.apple.com.key
TLSCertificatePassphraseTool /etc/httpd/getsslpassphrase dirt.apple.com:636 RSA
How mysterious! Gee, I wonder how that got there.
There are three strange / unwanted behaviors here. First is that the command-line 'serveradmin' does NOT have functional parity with the GUI Server Admin with respect to enabling SSL for OpenLDAP. The second is that a tool clearly positioned for Apache is being used by OpenLDAP. The third is that I have no idea where the getsslpassphrase looks for the SSL key password other than /etc/httpd/servermgr_web_httpd_config.plist. The getsslpassphrase tool does link against the Security framework, so I suppose it's possible that it's fishing it out of the System Keychain or something.
[[passage of time]]
Yep. There's an item in the System keychain called certificateManager of type 'application password' with 'Account' set to the fqdn used in the SSL certificate 'common name' attribute. Open that keychain entry and hit the 'show password' checkbox to display the SSL key password.
So then, the magic appears to be supplied by the OpenLDAP configuration directive "TLSCertificatePassphraseTool" and by the /etc/httpd/getsslpassphrase tool. Googling, we see that TLSCertificatePassphraseTool exists exactly once on all of the Internets: right here; clearly this is an Apple addition.
So now you should have all the pieces required to enable SSL for OpenLDAP from the command line:
- Import or create an SSL cert using Server Admin (this could probably also be done with the command line 'security' tool, but that's left as an exercise for the reader)
- Add the appropriate configuration to the slapd_macosxserver.conf file as shown above
- Add the appropriate configuration using the 'serveradmin' cli tool as shown above. This should cause slapd to restart using SSL (note that I haven't actually gone through each of these steps in this manner... wait for it...)
I found a much easier way to accomplish all this from the command line:
sudo slapconfig -setldapconfig -ssl on -sslcert /etc/certificates/dirt.apple.com.crt \\
-sslkey /etc/certificates/dirt.apple.com.key -ssldomain dirt.apple.com
At this point you're probably wishing I had just lead with that instead of dragging you through the mud first. Hey, it builds character :)
Finally I should note that on one of two test servers, the creation of the self-signed cert using Server Admin didn't totally work. What's supposed to happen is that it creates System keychain entries and then 'exports' those for use by OpenSSL, which looks for the files in /etc/certificates. The exporting part didn't seem to work properly on one server, however after executing
sudo certadmin export dirt.apple.com
the required files are published into /etc/certificates, and life is grand.