Native LDAP client configuration brings quite a few questions, especially regarding to SSL/TLS, so you can try to find answers in this blog
This note consist of the following sections:
- How SSL works
- Securing LDAP communication using SSL
- Configuring SSL-ed LDAP name services in Solaris OS
How SSL works
Traditionally, before start doing any configuration, consider SSL communication (at the concept level):
- Initially a client sends request to start SSL session,
providing a list of encryption algorithms it supports.
Client -- [ Start SSL Session Request ] --> Server
[ Enc. algorithms supported ]
- Server chooses "best" algorithm (normally a strongest one) and responds with own certificate, optionally server may request a client certificate.
Client <-- [ Enc. algorithm chosen ] -- Server
[ Server Certificate ] |
[ | +---------------------+ ] Enc. algorithm
[ +--| Subject | ]
[ | Exp. Date, etc. | ]
[ | Server's Public Key | ]
[ | Authority Signature | ]
[ +---------------------+ ]
[ Client Cert Req (optional) ]
- Client verifies certificate, i.e.
- Certificate must be consistent (client normally has CA public key, so can check CA signature and therefore certificate integrity);
- Authority must be configured as "trusted";
- Subject must correspond to a Server's hostname;
- Certificate must be not expired
- Optionally client may look at CA revokation list to find out whether CA revoked this certificate.
If certificate is verified successfully, a client makes some "session key" and sends it to server, encrypting by server's public key, taken from the certificate. Optionally, or on request, client may send its certificate as well.
Client ----- [ +------------------------+ ] --> Server
| [ | Session Key, encrypted | ] |
Enc. algorithm [ | by Server's public | ] Enc. algorithm
Session Key [ +------------------------+ ]
[ Client Cert (if needed) ]
- Server, in turn, has a chance to check client's certificate if needed. And now both client and server have each other authenticated, know symmetric encryption algorithm and the key, so they can communicate in secure way ...
Client <---- [ Message, encrypted ] ----> Server
| [ by the Session Key ] |
Enc. algorithm Enc. algorithm
Session Key Session Key
Securing LDAP communication using SSL
First of all, SSL in a Directory Server should be turned ON.
Obviously a server configuration depends on DS version, however in general, a Directory Server should somehow:
- listen secure port (whatever the port is, default is 636),
- know where certificates and keys are (device, names, etc.) and
- whether the client certificate is required or not or maybe optional.
I'm running Sun DS 6, so let's check what's going on there ...
# less <DS instance dir>/config/dse.ldif
nsslapd-secureport : 1636
nsSSLActivation : on
nsSSLPersonalitySSL : defaultCert
nsSSLToken : Internal (Software)
nsKeyfile : alias/slapd-key3.db
nsCertfile : alias/slapd-cert8.db
nsSSLClientAuth : allowed
Ok, settings are: listen 1636 port, activate SSL, use (
slapd-cert8.db,
slapd-key3.db) database, where server's certificate stored under
defaultCert name, and allow client authentication by a certificate. Look into this database more closely ...
# certutil -L \
-d <DS instance dir>/alias -P slapd- -n defaultCert
Subject: "CN=adorus,CN=1636,CN=Directory Server"
...
Note that in order to manage DS certificate database it's better to use
certutil [
1] from DS package itself, if such exists.
As an example DS 6 may have
certutil in
<DS install dir>/dsee6/bin.
However if the Directory Server distribution doesn't contain
certutil, use one from
/usr/sfw/bin, making sure its version is suitable.
Well, command output above shows that right after DS instance creation some default certificate exists, but we better create our own.
So, we can either create self-signed certificate for our Directory Server,
or use Certificate Authority for signing our DS certificate.
If you want to have a simple Cert Authority, here is a guide how to create it with help of
openssl(1):
- You need to generate a key for Cert Authority (1024 bit RSA for example)
$ openssl genrsa -out ca.key 1024
Generating RSA private key, 1024 bit long modulus
.................................................
e is 65537 (0x10001)
- Then generate self-signed X509 certificate for Cert Authority
$ openssl req -out ca.cert -key ca.key -new -x509 \
-days 365 -subj "/CN=Test Cert Authority"
- Create a config file, e.g.
$ cat ca.conf
[ ca ]
default_ca = TestCA # Default CA
[ TestCA ]
private_key = ca.key # CA key
certificate = ca.cert # CA certificate
database = ca.db # Keep track of certs issued
serial = ca.serial # Serial number for next cert
default_days = 365 # Validity for certs issued
default_md = md5 # Default message digest
policy = policy_cn # What should be in subject
new_certs_dir = . # Dir for newly created certs
[ policy_cn ]
commonName = supplied # CN must be supplied
- And finally create a database for keeping track of certs issued and a file containing serial number for the next signed certificate
$ touch ca.db
$ echo 01 >ca.serial
Ok, now go configure SSL on the server, so create database for storing keys and certificates
# certutil -N \
-d <DS instance dir>/alias -P ds-
Enter a password which will be used to encrypt your keys.
Enter new password:
Re-enter password:
Obtain required certificates and put them into the database created
- either by involving Cert Authority as follows
- Generate private key and a certificate request
# certutil -R \
-d <DS instance dir>/alias -P ds- \
-s "CN=adorus.sun.com" -k rsa -g 1024 \
-a -o adorus.cert.req
- Sign this request by the Cert Authority
$ openssl ca -config ca.conf -in adorus.cert.req -out adorus.cert
Using configuration from ca.conf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName :PRINTABLE:'adorus.sun.com'
Sign the certificate? [y/n]: y
1 out of 1 certificate requests certified, commit? [y/n] y
Write out database with 1 new entries
Data Base Updated
- Add signed certificate together with CA certificate to the database
# certutil -A \
-d <DS instance dir>/alias -P ds- \
-n adorus -t ,, -i adorus.cert
# certutil -A \
-d <DS instance dir>/alias -P ds- \
-n TestCA -t CT,, -i ca.cert
Note that trust attributes (-t) for CA should be "CT,," -- i.e. for SSL operations CA is trusted to issue server and client certificates, refer to certutil [1] doc, otherwise logs/errors shows the following:
SSL - conn=-1 op=-1 msgId=-1 - SSL is misconfigured:
Client authentication is enabled but no certificate
authority is trusted for SSL client authentication.
- or by creating just a self-signed certificate (that case "
T,," trust attributes should be ok)
# certutil -S \
-d <DS instance dir>/alias -P ds- \
-s "CN=adorus.sun.com" -n adorus -t T,, -x
IMPORTANT: A common name (CN) in DS certificate subject MUST be equal to DS hostname,
otherwise client won't be able to authorize DS by a certificate,
and therefore SSL communication will be denied.
Finally our certificate database looks good, server's certificate attributes are "
u,u,u", which means that database contains corresponding key for it, and therefore certificate can be used for authentication or signing -- that's required.
# certutil -L \
-d <DS instance dir>/alias -P ds-
adorus u,u,u
TestCA CT,,
# certutil -O \
-d <DS instance dir>/alias -P ds- -n adorus
"TestCA" [CN=Test Cert Authority]
"adorus" [CN=adorus.sun.com]
so do restart DS, reconfiguring SSL settings, i.e.
- Stop DS
# <DS install dir>/ds6/bin/dsadm stop <DS instance dir>
or
# <DS instance dir>/stop-slapd
- Modify DS configuration, edit
<DS instance dir>/config/dse.ldif, e.g.
nsslapd-secureport : 1636
nsSSLActivation : on
nsSSLPersonalitySSL : adorus
nsSSLToken : Internal (Software)
nsKeyfile : alias/ds-key3.db
nsCertfile : alias/ds-cert8.db
nsSSLClientAuth : allowed
- Start DS
# <DS install dir>/ds6/bin/dsadm start <DS instance dir>
or
# <DS instance dir>/start-slapd
Now Directory Server should work over SSL, let's check it out
- Make proper certificate database on the client, this time using standard
certutil, saying that we trust "TestCA" to issue server's certificates, e.g.
client $ certutil -A -d . -n TestCA -t C,, -i ca.cert
Or in case of DS certificate is self-signed, do export it from server's database and import into client's one, specifying that "adorus" is a "trusted peer"
adorus # certutil -L \
-d <DS instance dir>/alias -P ds- -n adorus -a >adorus.cert
client $ certutil -A -d . -n adorus -t P,, -i adorus.cert
- Try to query some data using
ldapsearch(1), as an example
$ ldapsearch -h adorus.sun.com -p 1636 -P cert8.db \
-D "cn=Directory Manager" -b "" -s base "" vendorVersion
vendorVersion: Sun-Java(tm)-System-Directory/6.0
IMPORTANT: Any violation in trust attribtues (
-t option in
certutil) or wrong host specification (
-h option in
ldapsearch), i.e. for example when server host name is differ from CommonName in server's certificate subject, cause
ldap_search: Can't contact LDAP server
Configuring SSL-ed LDAP name services in Solaris OS
Unfortunately, native LDAP client in Solaris OS (at lest in Nevada release 50) has several restrictions with respect to SSL/TLS:
- Secure port MUST be default (636), because
ldap_cachemgr(1M) doesn't accept port specification at all:
ldap_cachemgr: Configuration Error: Cannot specify LDAP port with tls
- Even if Directory Server is SSL configured, anyway non-secure port also MUST be open, moreover it MUST be default (389), otherwise
ldap_cachemgr(1M) during its startup will be just keep querying 389 port (which is closed) for some time and eventually ends up with "maintenance" mode, of course ...
# svcs -p ldap/client
STATE FMRI
offline* svc:/network/ldap/client:default
825 ldap_cachemgr
826 ldap_cachemgr
# snoop -v port 389 ldap
TCP: ----- TCP Header -----
TCP: Destination port = 389 (LDAP)
TCP: Sequence number = 2118718169
TCP: Acknowledgement number = 0
TCP: Flags = 0x02
TCP: .... ..1. = Syn
TCP: ----- TCP Header -----
TCP: Source port = 389 (LDAP)
TCP: Sequence number = 0
TCP: Acknowledgement number = 2118718170
TCP: Flags = 0x14
TCP: ...1 .... = Acknowledgement
TCP: .... .1.. = Reset
# svcs ldap/client
STATE FMRI
maintenance svc:/network/ldap/client:default
Hopefully these issues will be sorted out shortly, but for now in order to move further we need to set ports to defaults, sorry:
# less <DS instance dir>/config/dse.ldif
nsslapd-port: 389
nsslapd-secureport: 636
Assume we have LDAP name services repository established on our Directory Server by
idsconfig(1M) or by any other way.
Base DN is
dc=sun,dc=com and so we keep our Directory User Agent (DUA) profiles in
ou=profile,dc=sun,dc=com.
Then let's create DUA profile, for example with "
ssl" name, "
tls:simple" auth method and "
proxy" credential level, refer to
ldapclient(1M) for some description:
# ldapmodify <host, port, credentials, etc.> <<EOF
dn: cn=ssl,ou=profile,dc=sun,dc=com
changetype: add
cn: ssl
objectClass: top
objectClass: DUAConfigProfile
defaultServerList: 10.18.138.43
defaultSearchBase: dc=sun,dc=com
followReferrals: FALSE
defaultSearchScope: one
searchTimeLimit: 30
bindTimeLimit: 10
profileTTL: 43200
credentialLevel: proxy
authenticationMethod: tls:simple
EOF
Now we're ready to switch client to secure native LDAP name service ...
- Create certificate database in
/var/ldap, which is default for ldap/client service, with proper certificates:
client # certutil -A -d /var/ldap -n TestCA -t CT,, -i ca.cert
- Add corresponding entry to
/etc/hosts file (or whatever your name resolving process will use before it goes to LDAP), making DS address correspond to its host name, which as we know equals to a common name specified in server's certificate subject:
client # less /etc/hosts
10.18.138.43 adorus.sun.com
Without that ldap_cachemgr reports an error:
ldap_cachemgr[1016]: Error: Unable to refresh profile:
Session error no available conn.
- Initialize LDAP client by
ldapclient(1M), e.g.
client # ldapclient init -a profileName=ssl -a domainName=sun.com \
-a proxyDN=<proxy user DN> -a proxyPassword=<password> \
adorus.sun.com
Or if you have LDAP client already working via non-SSL communication, you may
- change
NS_LDAP_PROFILE value in /var/ldap/ldap_client_file to our secure profile name, which is ssl in our example,
- and then restart
ldap_cachemgr(1M), which is actually ldap/client service.
Finally, SSL-ed native LDAP client should work, let's test it:
client # ldaplist -vl passwd user1
+++ database=passwd
+++ filter=(&(objectclass=posixaccount)(uid=user1))
+++ template for merging SSD filter=(&(%s)(uid=user1))
dn: uid=user1,ou=people,dc=sun,dc=com
objectClass: shadowAccount
objectClass: posixAccount
objectClass: top
uid: user1
cn: test user
uidNumber: 201
gidNumber: 10
homeDirectory: /tmp
loginShell: /bin/sh
userPassword: {crypt}wqpIrejx8/QKQ
Good, we're done now.
References
[1]
Using the Certificate Database Tool
Trackback URL: http://blogs.sun.com/vl/entry/native_solaris_ldap_client_over