[toc]
Software Requirements
=====================
Beyond the usual distribution of choice, there are no special software requirements for installing and running the OpenLDAP server for the purpose of maintaining a certification storage.
Installing Required Packages
============================
Installation of the OpenLDAP server can be done by a simple:
```
? root
$ apt-get install slapd
```
During installation the package installer will prompt you to provide administrator password.
There are many tools which can be used for communicating with the LDAP servers. A set of standard tools can be installed with:
```
? root
$ apt-get install ldap-utils
```
Part of the command-line options used with the LDAP utils can be moved to a distinct configuration file. This way the most sane defaults can be set. Configure the global LDAP client configuration file:
```
# /etc/ldap/ldap.conf
----BEGIN----
BASE dc=example,dc=com
URI ldap://ldap.example.com
-----END-----
```
After that set-up the *root*-specific configuration file for binding to a specific LDAP account (in this case the administrator account):
```
# /root/.ldaprc
----BEGIN----
BINDDN cn=admin,dc=example,dc=com
-----END-----
```
Setting-up LDAP Tree
====================
Designing and setting-up the LDAP tree is a very challenging task. It usually takes several iterations and installations to actually figure out a proper design, and design procedures can actually form a book of its own. For the purpose of this cookbook the LDAP tree will be set-up as follows:
```
dc=example,dc=com
ou=people
ou=services
```
The *ou=people,dc=example,dc=com* sub-tree will contain information about people within the organisation, including their login credentials, general information, and certificates.
The *ou=services,dc=example,dc=com* tree will contain information about the services provided within the organisation, their certificates, data, and login credentials for accessing the LDAP database (where appropriate).
The entries in the LDAP tree will be added through LDIF files. The files will be laid-out in such a way as to resemble the tree with their directory/file structure/names.
Create a directory which will contain the LDIF's for adding these entries on LDAP server:
```
? root
$ mkdir -p ~/ldap/dc=example,dc=com/
```
Create an LDIF file for the services sub-tree:
Create an LDIF file for the people tree:
```
# /root/ldap/dc=example,dc=com/ou=people.ldif
----BEGIN----
dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: people
-----END-----
```
Create an LDIF file for the services tree:
```
# /root/ldap/dc=example,dc=com/ou=services.ldif
----BEGIN----
dn: ou=services,dc=example,dc=com
objectClass: organizationalUnit
ou: services
-----END-----
```
Now add those entries with:
```
? root
$ ldapadd -x -W -f /root/ldap/dc=example,dc=com/ou=people.ldif
$ ldapadd -x -W -f /root/ldap/dc=example,dc=com/ou=services.ldif
```
We will now create an entry for the EJBCA which will be used for accessing the LDAP database.
Create the sub-directory which will contain LDIF files for the *ou=services* sub-tree:
```
? root
$ mkdir -p ~/ldap/dc=example,dc=com/ou=services/
```
Create an LDIF file which will contain the log-in information for the service:
```
# /root/ldap/dc=example,dc=com/ou=services/cn=Example CA Server.ldif
----BEGIN----
dn: cn=Example CA Server,ou=services,dc=example,dc=com
objectClass: applicationProcess
objectClass: simpleSecurityObject
objectClass: extensibleObject
cn: Example CA Server
description: Certification authority
userPassword: {{ejbca_ldap_password}}
-----END-----
```
The *ejbca_ldap_password* parameter should be provided as a password in hashed form produced by the following command:
```
? root
$ slappasswd -h '{SSHA}'
```
Import the LDIF entry into database:
```
? root
$ ldapadd -x -W -f /root/ldap/dc=example,dc=com/ou=services/cn=Example\ CA\ Server.ldif
```
Setting-up LDAP Permissions
===========================
Setting-up proper LDAP permissions is an important task, although commonly a tedious ones. It can take quite a bit of time to tweak them properly. Failure to set them up properly can lead to anything from inability to access the information to secure data disclosure to untrusted parties.
In the past the *slapd* daemon used to be configured through a plain textual configuration file, but the preferred method in the meantime has become use of special configuration database backend which allows for on-the-fly changes in configuration. Unfortunately, in addition to advantages (like no need for restart for almost all changes), this also introduces some annoyances when it comes down to ease of use.
Create a directory which will contain the LDIF files for modifying the configuration:
```
? root
$ mkdir -p ~/ldap/config
```
The easiest way to alter the access control rules in *slapd* is to replace the entire access control rules with new ones. Although this can be done through a single LDIF file, it could be useful to separate the process into two steps since removal of non-existent attributes stops the processing of LDIF file.
Set-up an LDIF file used for removing all access control attributes from the configuration database:
```
# /root/ldap/config/remove_accessrules.ldif
----BEGIN----
dn: olcDatabase={1}hdb,cn=config
changetype: modify
delete: olcAccess
-----END-----
```
Set-up an LDIF file which will set the access rules:
```
# /root/ldap/config/add_accessrules.ldif
----BEGIN----
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: to dn.base=""
by * read
-
add: olcAccess
olcAccess: to attrs=userPassword
by anonymous auth
by * none
-
add: olcAccess
olcAccess: to dn.base="dc=example,dc=com"
by * read
-
add: olcAccess
olcAccess: to dn.subtree="ou=people,dc=example,dc=com"
by dn="cn=Example CA Server,ou=services,dc=example,dc=com" write
by users read
by * none
-
add: olcAccess
olcAccess: to dn.subtree="ou=services,dc=example,dc=com"
by dn="cn=Example CA Server,ou=services,dc=example,dc=com" write
by users read
by * none
-----END-----
```
Now apply the changes:
```
? root
$ ldapmodify -Y EXTERNAL -H ldapi:/// -f /root/ldap/config/remove_accessrules.ldif
$ ldapmodify -Y EXTERNAL -H ldapi:/// -f /root/ldap/config/add_accessrules.ldif
```
After this you may want to attempt some searches to verify that access control set in place is functioning properly:
```
? root
$ ldapsearch -x -W -D 'cn=Example CA Server,ou=services,dc=example,dc=com'
```
Setting-up Certificates
=======================
The OpenLDAP server supports both the *STARTTLS* and pure *SSL* for securing the communication. In addition to using them for simply encrypting the protocol, they can also be used for client-certificate authentication (this is covered within a separate chapter of the cookbook).
For start it's necessary to issue the key/certificate pair for the server. Go to the *Administration -> Add End Entity* page, select the *Server* end entity profile, and fill-in the following information:
```
Username: ldap.example.com_ldap
Password: {{ldap_end_entity_password}}
Confirm Password: {{ldap_end_entity_password}}
Batch generation (clear text pwd storage): Off
E-mail address: ldap@example.com
CN, Common name: Example LDAP Server
O, Organization: Example Inc.
C, Country (ISO 3166): RS
DNS Name: ldap.example.com
Certificate Profile: Example Server
CA: Example Server CA
Token: PEM file
```
Replace the *ldap_end_entity_password* parameter with desired password.
Click on the *Add* button once done. Now go to the *Public Web -> Create Keystore* page. Provide the following information:
```
Username: ldap.example.com
Password: {{ldap_end_entity_password}}
```
Click on the *OK* button. In the new page select the key length of *4096 bits* and click on the *OK* button. Save the resulting *ldap.example.com_ldap.pem* file onto your workstation. The *pem* file should be now split into two separate files - *ldap.example.com.key* and *ldap.example.com.crt*. The *key* file should contain only the private key portion of the *ldap.example.com_ldap.pem* file, while the *crt* file should contain only the certificate.
In addition, this key needs to be converted since the *slapd* daemon won't be capable of reading the key in its default (PKCS#8) form. Instead, the key needs to be provided in *PKCS#1* format. Instead of extracting the key with copy/paste, the conversion and extraction can be performed directly on the original *pem* filed with the following command:
```
$ openssl rsa -in ldap.example.com_ldap.pem -out ldap.example.com.key
```
Place these files in the following directory on the *ldap.example.com* server:
```
# /etc/ldap/
```
Set-up the file permissions for the private key and certificate:
```
? root
$ chown root.openldap /etc/ldap/ldap.example.com.{key,crt}
$ chmod 640 /etc/ldap/ldap.example.com.{key,crt}
```
Finally, it's necessary to modify the configuration on the LDAP server to enable TLS. Create the following LDIF file:
```
# /root/ldap/config/tls.ldif
----BEGIN----
dn: cn=config
changetype: modify
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/ldap.example.com.crt
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/ldap.example.com.key
-----END-----
```
Apply the change:
```
? root
$ ldapmodify -Y EXTERNAL -H ldapi:/// -f /root/ldap/config/tls.ldif
```
Since EJBCA supports only plain SSL connections, also make sure that *slapd* is listening on the default *ldaps* port:
```
# /etc/default/slapd
----BEGIN----p
--- SLAPD_SERVICES="ldap:/// ldapi:///"
+++ SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"
-----END-----p
```
Unfortunately, the change of protocols used by slapd for communication and changes to TLS usage are the only changes that yield restart of the *slapd* service. You should do this with:
```
? root
$ service slapd restart
```
Setting-up LDAP Publisher on EJBCA
==================================
What's left to be done is to set-up the EJBCA to publish the certificates to the LDAP database. Open the EJBCA web interface and go to the *Administration -> Edit Publishers* page.
Enter *LDAP Person Publisher* as the name of the publisher, then click on the *Add* button. Select the newly-crated publisher from the list and click on the *Edit Publisher* button. Make the following changes:
```
Publisher Type: LDAP V3 Publisher
Hostnames: ldap.example.com
Base DN: ou=people,dc=example,dc=com
Login DN: cn=Example CA Server,ou=services,dc=example,dc=com
Login Password: {{ldap_end_entity_password}}
Confirm Password: {{ldap_end_entity_password}}
Overwrite Existing Attributes: On
Add multiple certificates per user: On
LDAP location fields from cert DN: UID, Unique Identifier
No direct publishing, only use queue: Off
Description: Publisher for storing person certificates in the LDAP database.
```
Parameter *ldap_end_entity_password* should be replaced by the password used earlier during set-up of the LDAP tree.
Click on the *Save and Test Connection* button to verify the configuration, and then click on the *Save* button to go back to the list of publishers.
The next thing in line is to add a publisher for the server certificates. While this is not strictly necessary, it could be useful for the sake of completeness.
Select the *LDAP Person Publisher* from the list, enter *LDAP Server Publisher* as a new publisher name and click on the *Use selected as template* button. Select the newly-created publisher from the list, click on the *Edit Publisher* button and make the following changes:
```
Base DN: ou=services,dc=example,dc=com
User Object Class: top;applicationProcess;extensibleObject
LDAP location fields from cert DN: CN, Common name
Description: Publisher for storing server certificates in the LDAP database.
```
Once the information has been filled-in, click on the *Save and Test Connection* button to verify the configuration, and then on the *Save* button to return to the list of publishers.
With publishers configured and in place, it's time to tell EJBCA which certificate profiles will yield publishing to the LDAP database. Go to the *Administration -> Edit Certificate Profiles* page. Select the *Example Person Signing* profile and click on the *Edit Certificate Profile* button. Make the following change:
```
Publishers: LDAP Person Publisher, OCSP Publisher
```
Click on the *Save* button and then make the same change for the *Example Person Encryption* profile.
Now for the server profiles. Repeat the following procedure for *Example Server*, *Example MySQL Server* and *Example OCSP Signer* profiles. Select the profile and click on the *Edit Certificate Profile*. Make the following change:
```
Publishers: LDAP Server Publisher, OCSP Publisher
```
Click on the *Save* button to apply the changes.
Let's make the *Publish Queue Process Service* take care of the new publishers as well. Go to the *Administration -> Edit Services* page and select the *Publish Queue Process Service* from the list. Click on the *Edit Service* button. Make sure to mark the *LDAP Person Publisher* and *LDAP Server Publisher* in the *Publishers to check* list (in addition to any of the already selected publishers). Click on the *Save* button to apply the changes.
We can finally start publishing the certificates into the LDAP database. The easiest way to do this is by logging-in onto the *ca.example.com* server and executing the following commands:
```
? ejbca
$ cd /opt/ejbca/
$ bin/ejbca.sh ca republish 'Example Person CA'
$ bin/ejbca.sh ca republish 'Example Server CA'
```
This will force any previously-generated certificates to be republished using all of the activated publishers, which concludes the set-up of certificate repository. Afterwards any new certificates will be automatically published to the LDAP database, and any revoked certificates will be removed from it.
Verifying the Publishing
========================
The easiest way to verify that the certificates are getting published is to check the contents of the LDAP database itself. This can be done with a number of graphical tools as well as console tools.
Once you have republished the certificates you can search the database for the certificate attributes with the following command on the *ldap.example.com*:
```
? root
$ ldapsearch -Y EXTERNAL -H ldapi:/// '(userCertificate=*)' userCertificate
```
This command will return DN's (LDAP ones, not certificate ones) which have a certificate attribute coupled with the certificate attribute contents itself (BASE64-encoded).
Troubleshooting
===============
**When publishing a CRL I get `Message: Object Class Violation`**
While the guide does not describe how to set this up (so you have done your own thing), you might be getting a stack trace similar to:
```
javax.ejb.EJBException: javax.ejb.EJBException: Error creating CRL.
.
.
.
Caused by: javax.ejb.EJBException: Error creating CRL.
.
.
.
Caused by: javax.ejb.EJBException: org.ejbca.core.model.ca.publisher.PublisherException: LDAP ERROR: Error storing CRL (certificateRevocationList;binary) in LDAP (top;applicationProcess;certificationAuthority-V2) for DN (CN=SubCAPerson,O=Home,C=RS,dc=pki-nss,dc=bloublou). Message: Object Class Violation.
.
.
.
Caused by: org.ejbca.core.model.ca.publisher.PublisherException: LDAP ERROR: Error storing CRL (certificateRevocationList;binary) in LDAP (top;applicationProcess;certificationAuthority-V2) for DN (CN=SubCAPerson,O=Home,C=RS,dc=pki-nss,dc=bloublou). Message: Object Class Violation.
```
The problem is that when the CRLs are being published, EJBCA does not create the necessary structure in the LDAP directory. Solution is to republish the CA certificates first so the necessary entries would get created.
**Does file `/root/.ldaprc` already exist or should I create a new file?**
This file is normally not present after fresh install, so you will need to create it yourself.