Software Requirements[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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[edit]

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.