<!--

Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.

The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.

See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.

-->
<chapter id="csdk-ssl"><title>SSL Connections With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
</indexterm><highlights>
<para>This chapter describes the process of enabling an LDAP client to connect
to an LDAP server over the Secure Sockets Layer (SSL) protocol.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdahz">How SSL Works With Directory SDK
for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaia">Connecting to a Server Over SSL With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaic">Handling Errors With Directory SDK
for C</olink></para></listitem>
<listitem><para><olink targetptr="ssl-start-tls">Starting Transport Layer
Security With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaid">Installing Your Own SSL I/O Functions
With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaie">Using Certificate-Based Client Authentication
With Directory SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdahz"><title>How SSL Works With &DirectorySDKForC;</title>
<para>The primary goal of the SSL protocol is to provide privacy and reliability
between two communicating applications.</para>
<note><para>SSL is not supported on all LDAP servers.</para><para>SSL communication
must take place on a separate TCP port unless the server supports Start TLS.</para>
</note>
<para>When an LDAP client connects to an LDAP server over SSL, the server
identifies itself by sending a certificate to the client. The client needs
to determine whether or not the certificate authority (CA) that issued the
certificate is trusted. The client therefore searches a certificate database
for the certificate of the CA. If the client cannot find the certificate,
the client refuses to connect to the server. If the certificate is marked <firstterm>
not trusted</firstterm>, the client also refuses to connect to the server.</para>
<para>The LDAP server can also request that the client send a certificate
to authenticate itself. This part of the process is called <firstterm>certificate-based
client authentication</firstterm>. If the client receives a request for a
certificate from the server, the client retrieves its certificate from the
certificate database. The client sends the certificate to the server for authentication.
After receiving the client&rsquo;s certificate, the LDAP server determines
whether or not the CA that issued the certificate is trusted. If the server
cannot find the CA certificate in the certificate database, the server refuses
to authenticate the client. If the CA certificate is marked as <firstterm>not
trusted</firstterm>, the server also refuses to authenticate the client. If
the CA is trusted, the server uses the certificate subject name to determine
whether the client has access to perform the requested operation.</para>
<itemizedlist>
<para>&DirectorySDKForC; includes functions that allow you to connect an
LDAP client to an LDAP server over SSL. The functions make the following assumptions:
</para>
<listitem><para>Your client has access to a certificate database. The function
call uses this certificate database to determine if the client can trust the
certificate sent from the server.</para><para>Different certificate database
versions can be incompatible, which might result in database errors.</para>
</listitem>
<listitem>
<itemizedlist>
<para>The database used contains any one of the following:</para>
<listitem><para>The certificate of the CA that issued the server&rsquo;s certificate
</para></listitem>
<listitem><para>If the CAs are organized in a hierarchy, the certificate of
any of the CAs in the hierarchy</para></listitem>
<listitem><para>The certificate of the LDAP server</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>The CA certificate is marked as <firstterm>trusted</firstterm> in
the certificate database.</para></listitem>
<listitem>
<itemizedlist>
<para>If you plan to use certificate-based client authentication, you also
need the following:</para>
<listitem><para>A client certificate in the certificate database issued by
a CA that is trusted by the LDAP server</para></listitem>
<listitem><para>A public-private key pair in a key file</para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<itemizedlist>
<para>The functions allow you to do the following:</para>
<listitem><para>Set the session option for communicating with the server over
SSL.</para><para>See <olink targetptr="bdaia">Connecting to a Server Over
SSL With Directory SDK for C</olink> for details.</para></listitem>
<listitem><para>Start transport layer security by using the Start TLS extended
operation</para><para>See <olink targetptr="ssl-start-tls">Starting Transport
Layer Security With Directory SDK for C</olink> for details.</para></listitem>
<listitem><para>Replace the default I/O functions with your own I/O functions
for communicating over SSL</para><para>See <olink targetptr="bdaid">Installing
Your Own SSL I/O Functions With Directory SDK for C</olink> for details.</para>
</listitem>
<listitem><para>Enable your client to send certificates to authenticate itself</para>
<para>See <olink targetptr="bdaie">Using Certificate-Based Client Authentication
With Directory SDK for C</olink> for details.</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="bdaia"><title>Connecting to a Server Over SSL With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>connecting to the server</tertiary>
</indexterm>
<para>To enable your LDAP client to connect to an LDAP server with SSL, you
need to perform the following procedure.</para>
<task><title>To Initialize a Client SSL Connection by Using <function>ldapssl_init
</function></title>
<procedure>
<step><para>Initialize your client by calling one of the following functions:</para>
<substeps>
<step><para>Call <function>ldapssl_client_init</function> if you do not plan
to use certificate-based client authentication.</para></step>
<step><para>Call <function>ldapssl_clientauth_init</function> if you plan
to use certificate-based client authentication.</para></step>
<step><para>Call <function>ldapssl_advclientauth_init</function>.</para><para>If
you use certificate-based client authentication, you need to specify the path
of the security module database, or to specify the method to verify the server
certificate.</para></step></substeps>
<para>You must initialize your client before initializing the LDAP session.
The process of initializing the client opens the certificate database.</para>
</step>
<step><para>Initialize an LDAP session with the secure server by calling the <function>
ldapssl_init</function> function.</para><para>For an alternative way to accomplish
this step, see <olink targetptr="bdaib">Alternative to ldapssl_init</olink>.</para>
</step>
</procedure>
<example id="ssl-init-connection-example">
<title>To Initialize a Client SSL Connection by using <function>ldapssl_init</function></title>
<para>This example initializes a client to connect to a secure LDAP server
over SSL.</para>
<programlisting>if ( ldapssl_client_init( "/local/examples/alias/", NULL ) &lt; 0) {
  printf( "Failed to initialize SSL client...\n" );
  return( 1 );
}
/* get a handle to an LDAP connection */
if ( (ld = ldapssl_init( "cert.example.com", LDAPS_PORT, 1 )) == NULL {
  perror( "ldapssl_init" );
  return( 1 );
}
...
/* Client can now perform LDAP operations on the secure LDAP server. */
...</programlisting>
</example>
</task>
<sect2 id="bdaib"><title>Alternative to <function>ldapssl_init</function></title>
<para>As an alternative to calling the <function>ldapssl_init</function> function,
you can use the following procedure.</para>
<task><title>To Initialize a Client SSL Connection (Alternative Method Using <function>
ldap_init</function></title>
<procedure>
<step><para>After initializing your client, initialize an LDAP session with
the server by calling the standard initialization function <function>ldap_init</function>.
</para></step>
<step><para>Install the standard SSL I/O functions by calling <function>ldapssl_install_routines
</function>.</para></step>
<step><para>Set the SSL option in the LDAP structure by calling <function>ldap_set_option
</function>.</para></step>
</procedure>
<example id="ssl-init-alt-connection-example">
<title>Initializing a Client SSL Initialization (Alternative Method Using <function>
ldap_init</function>)</title>
<para>This example prepares a client to connect to a secure LDAP server over
SSL using <function>ldap_init</function>.</para>
<programlisting>if ( ldapssl_client_init( "/local/examples/alias/", NULL ) &lt; 0) {
  printf( "Failed to initialize SSL client...\n" );
  return( 1 );
}
/* Initialize LDAP session. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( MY_HOST, LDAPS_PORT )) == NULL ) {
  perror( "ldap_init" );
  return( 1 );
}

/* Load SSL routines */
if ( ldapssl_install_routines( ld ) != 0 ) {
  ldap_perror( ld, "ldapssl_install_routines" );
  return( 1 );
}
/* Set up option in LDAP struct for using SSL */
if ( ldap_set_option( ld, LDAP_OPT_SSL, LDAP_OPT_ON ) != 0 ) {
  ldap_perror( ld, "ldap_set_option" );
  return( 1 );
}
/* Client can now perform LDAP operations on the secure LDAP server. */
...</programlisting>
</example>
</task>
</sect2>
</sect1>
<sect1 id="bdaic"><title>Handling Errors With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>handling errors</tertiary>
</indexterm>
<para>After calling any of the SSL initialization functions, you can convert
SSL-specific error codes to text strings by calling <function>ldapssl_err2string</function>.
The <function>ldapssl_err2string</function> function provides support for
special SSL error messages that are not handled by the normal error conversion
routine <function>ldap_err2string</function>. </para></sect1>
<sect1 id="ssl-start-tls"><title>Starting Transport Layer Security With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>start TLS</tertiary>
</indexterm>
<para><ulink url="http://www.ietf.org/rfc/rfc4513.txt" type="text_url">RFC
4513</ulink>, <citetitle>Lightweight Directory Access Protocol (LDAP): Authentication
Methods and Security Mechanisms</citetitle>, describes the extended operation.
Start TLS allows you to connect to a nonsecure port, and then request transport
layer security.</para>
<task><title>To Use Start TLS</title>
<procedure>
<step><para>Initialize your client with <function>ldapssl_client_init</function>.
</para><para>The process of initializing the client opens the certificate
database.</para></step>
<step><para>Get a handle to an LDAP connection.</para></step>
<step><para>Request Start TLS with <function>ldap_start_tls_s</function>.</para>
</step>
<step><para>Authenticate to the directory to perform additional operations.</para>
</step>
</procedure>
<example>
<title>Using Start TLS</title>
<para>This example connects and uses Start TLS, then requests the Who am I?
extended operation. The example relies on a certificate database directory, <filename
class="directory">/local/examples/alias/</filename>.</para>
<programlisting>/*
 * Use the Start TLS extended operation.
 */

#include "examples.h"
#include &lt;ldap_ssl.h>

/*
 * Path to certificate database for SSL
 */
#define CERT_DB_PATH    "/local/examples/alias/"

int
main( int argc, char **argv )
{
    int             version;
    LDAP            *ld;
    int             rc;
    char            *authzid;

    /* Initialize access to the certificate database. */
    if ( ldapssl_client_init( CERT_DB_PATH, NULL ) != 0 ) {
        fprintf( stderr, "ldapssl_client_init failed\n" );
        fprintf( stderr, "certificate database path: %s\n", CERT_DB_PATH );
        return( 1 );
    }

    /* Use LDAPv3. */
    version = LDAP_VERSION3;
    if ( ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &amp;version )
         != 0 ) {
        fprintf( stderr,
                 "ldap_set_option protocol version to %d failed\n",
                 version );
        return( 1 );
    }

    /* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
    if ( (ld = ldap_init( MY_HOST, MY_PORT )) == NULL ) {
        perror( "ldap_init" );
        return( 1 );
    }

    /* Request Start TLS. */
    if ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
        ldap_perror( ld, "ldap_start_tls_s" );
        return( 1 );
    }
    printf( "Start TLS operation successful.\n" );

    /* Authenticate to the directory. */
    if ( ldap_simple_bind_s( ld, ENTRYDN, ENTRYPW ) != LDAP_SUCCESS ) {
        ldap_perror( ld, "ldap_simple_bind_s" );
        return( 1 );
    }

    /* Examine my authorization ID. */
    if ( (rc = ldap_whoami_s( ld, NULL, NULL, &amp;authzid ) )
         != LDAP_SUCCESS ) {
        fprintf( stderr, "ldap_whoami_s: %s\n", ldap_err2string( rc ) );
        ldap_unbind( ld );
        return( 1 );
    }
    printf( "Authorization ID: %s\n", authzid );

    ldap_unbind( ld );
    return( 0 );
}</programlisting>
<para>See <olink targetptr="extendop-whoami">Performing a Who Am I? Extended
Operation With Directory SDK for C</olink> for details on using the &ldquo;Who
am I?&rdquo; extended operation.</para></example>
<taskrelated role="troubleshooting">
<para>To troubleshoot Start TLS problems, call the <function>PR_GetError</function> function.
This function gives you access to many Network Security Services (NSS) errors
further documented in the <ulink
url="http://www.mozilla.org/projects/security/pki/nss/ref/ssl/sslerr.html"
type="text_url">Mozilla.org SSL Reference</ulink>.</para></taskrelated>
</task>
</sect1>
<sect1 id="bdaid"><title>Installing Your Own SSL I/O Functions With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>custom I/O functions</tertiary>
</indexterm>
<para>The <function>ldapssl_init</function> and <function>ldapssl_install_routines
</function> functions both set up the session to use the standard SSL I/O
functions provided with &DirectorySDKForC;. If you want to use your own
SSL I/O functions, use the <structname>ldap_x_ext_io_fns</structname> structure.</para>
<task><title>To Install Your Own SSL I/O Functions</title>
<procedure>
<step><para>Create an <structname>ldap_x_ext_io_fns</structname> structure,
and set the fields to point to your I/O functions.</para></step>
<step><para>Call <function>ldap_set_option</function> to point to that structure.
</para>
<programlisting>if (ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &amp;my_io_struct) != 0 ) {
    ldap_perror( ld, "ldap_set_option" );
    return( 1 );
}</programlisting>
</step>
</procedure>
</task>
</sect1>
<sect1 id="bdaie"><title>Using Certificate-Based Client Authentication With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>certificate-based authentication</tertiary>
</indexterm>
<para>Some LDAP servers can be configured to use certificate-based client
authentication. The server requests that your client send a certificate to
identify itself. Use the following procedure to configure your client to use
certificates for authentication.</para>
<task><title>To Use Certificate-Based Client Authentication</title>
<procedure>
<step><para>Initialize your LDAP client by calling either <function>ldapssl_clientauth_init
</function> or <function>ldapssl_advclientauth_init</function>, not <function>ldapssl_client_init
</function>.</para><para>U<?Pub Caret1>se <function>ldapssl_advclientauth_init</function> if
you want to specify the path of a security module database, or to specify
the method used to verify the server certificate.</para><para>You can use
one of these functions to initialize your client even if you do not plan to
use certificate-based client authentication. The functions are equivalent
to <function>ldapssl_client_init</function>.</para></step>
<step><para>Initialize an LDAP session with the secure server by calling <function>
ldapssl_init</function>.</para></step>
<step><para>Enable your client to authenticate with the secure server by calling <function>
ldapssl_enable_clientauth</function>.</para></step>
<step><para>Perform a Simple Authentication and Security Layer (SASL) bind
operation by using the mechanism <literal>EXTERNAL</literal>. This mechanism
indicates to the directory server that certificates should be used to authenticate
clients.</para><para>With &cnDirectoryServer;, if you perform a SASL bind
operation, but the server cannot find the corresponding directory entry for
a client certificate, the server returns an <literal>LDAP_INVALID_CREDENTIALS</literal> result
code with the error message <literal>Client Certificate Mapping Failed</literal>.
</para></step>
</procedure>
</task>
</sect1>
</chapter>
