SSL Connections With &DirectorySDKForC; C SDK Secure Sockets Layer (SSL) This chapter describes the process of enabling an LDAP client to connect to an LDAP server over the Secure Sockets Layer (SSL) protocol. This chapter covers the following topics: How SSL Works With Directory SDK for C Connecting to a Server Over SSL With Directory SDK for C Handling Errors With Directory SDK for C Starting Transport Layer Security With Directory SDK for C Installing Your Own SSL I/O Functions With Directory SDK for C Using Certificate-Based Client Authentication With Directory SDK for C How SSL Works With &DirectorySDKForC; The primary goal of the SSL protocol is to provide privacy and reliability between two communicating applications. SSL is not supported on all LDAP servers.SSL communication must take place on a separate TCP port unless the server supports Start TLS. 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 not trusted, the client also refuses to connect to the server. The LDAP server can also request that the client send a certificate to authenticate itself. This part of the process is called certificate-based client authentication. 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’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 not trusted, 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. &DirectorySDKForC; includes functions that allow you to connect an LDAP client to an LDAP server over SSL. The functions make the following assumptions: 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.Different certificate database versions can be incompatible, which might result in database errors. The database used contains any one of the following: The certificate of the CA that issued the server’s certificate If the CAs are organized in a hierarchy, the certificate of any of the CAs in the hierarchy The certificate of the LDAP server The CA certificate is marked as trusted in the certificate database. If you plan to use certificate-based client authentication, you also need the following: A client certificate in the certificate database issued by a CA that is trusted by the LDAP server A public-private key pair in a key file The functions allow you to do the following: Set the session option for communicating with the server over SSL.See Connecting to a Server Over SSL With Directory SDK for C for details. Start transport layer security by using the Start TLS extended operationSee Starting Transport Layer Security With Directory SDK for C for details. Replace the default I/O functions with your own I/O functions for communicating over SSLSee Installing Your Own SSL I/O Functions With Directory SDK for C for details. Enable your client to send certificates to authenticate itself See Using Certificate-Based Client Authentication With Directory SDK for C for details. Connecting to a Server Over SSL With &DirectorySDKForC; C SDK Secure Sockets Layer (SSL) connecting to the server To enable your LDAP client to connect to an LDAP server with SSL, you need to perform the following procedure. To Initialize a Client SSL Connection by Using <function>ldapssl_init </function> Initialize your client by calling one of the following functions: Call ldapssl_client_init if you do not plan to use certificate-based client authentication. Call ldapssl_clientauth_init if you plan to use certificate-based client authentication. Call ldapssl_advclientauth_init.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. You must initialize your client before initializing the LDAP session. The process of initializing the client opens the certificate database. Initialize an LDAP session with the secure server by calling the ldapssl_init function.For an alternative way to accomplish this step, see Alternative to ldapssl_init. To Initialize a Client SSL Connection by using <function>ldapssl_init</function> This example initializes a client to connect to a secure LDAP server over SSL. if ( ldapssl_client_init( "/local/examples/alias/", NULL ) < 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. */ ... Alternative to <function>ldapssl_init</function> As an alternative to calling the ldapssl_init function, you can use the following procedure. To Initialize a Client SSL Connection (Alternative Method Using <function> ldap_init</function> After initializing your client, initialize an LDAP session with the server by calling the standard initialization function ldap_init. Install the standard SSL I/O functions by calling ldapssl_install_routines . Set the SSL option in the LDAP structure by calling ldap_set_option . Initializing a Client SSL Initialization (Alternative Method Using <function> ldap_init</function>) This example prepares a client to connect to a secure LDAP server over SSL using ldap_init. if ( ldapssl_client_init( "/local/examples/alias/", NULL ) < 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. */ ... Handling Errors With &DirectorySDKForC; C SDK Secure Sockets Layer (SSL) handling errors After calling any of the SSL initialization functions, you can convert SSL-specific error codes to text strings by calling ldapssl_err2string. The ldapssl_err2string function provides support for special SSL error messages that are not handled by the normal error conversion routine ldap_err2string. Starting Transport Layer Security With &DirectorySDKForC; C SDK Secure Sockets Layer (SSL) start TLS RFC 4513, Lightweight Directory Access Protocol (LDAP): Authentication Methods and Security Mechanisms, describes the extended operation. Start TLS allows you to connect to a nonsecure port, and then request transport layer security. To Use Start TLS Initialize your client with ldapssl_client_init. The process of initializing the client opens the certificate database. Get a handle to an LDAP connection. Request Start TLS with ldap_start_tls_s. Authenticate to the directory to perform additional operations. Using Start TLS This example connects and uses Start TLS, then requests the Who am I? extended operation. The example relies on a certificate database directory, /local/examples/alias/. /* * Use the Start TLS extended operation. */ #include "examples.h" #include <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, &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, &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 ); } See Performing a Who Am I? Extended Operation With Directory SDK for C for details on using the “Who am I?” extended operation. To troubleshoot Start TLS problems, call the PR_GetError function. This function gives you access to many Network Security Services (NSS) errors further documented in the Mozilla.org SSL Reference. Installing Your Own SSL I/O Functions With &DirectorySDKForC; C SDK Secure Sockets Layer (SSL) custom I/O functions The ldapssl_init and ldapssl_install_routines 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 ldap_x_ext_io_fns structure. To Install Your Own SSL I/O Functions Create an ldap_x_ext_io_fns structure, and set the fields to point to your I/O functions. Call ldap_set_option to point to that structure. if (ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &my_io_struct) != 0 ) { ldap_perror( ld, "ldap_set_option" ); return( 1 ); } Using Certificate-Based Client Authentication With &DirectorySDKForC; C SDK Secure Sockets Layer (SSL) certificate-based authentication 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. To Use Certificate-Based Client Authentication Initialize your LDAP client by calling either ldapssl_clientauth_init or ldapssl_advclientauth_init, not ldapssl_client_init .Use ldapssl_advclientauth_init if you want to specify the path of a security module database, or to specify the method used to verify the server certificate.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 ldapssl_client_init. Initialize an LDAP session with the secure server by calling ldapssl_init. Enable your client to authenticate with the secure server by calling ldapssl_enable_clientauth. Perform a Simple Authentication and Security Layer (SASL) bind operation by using the mechanism EXTERNAL. This mechanism indicates to the directory server that certificates should be used to authenticate clients.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 LDAP_INVALID_CREDENTIALS result code with the error message Client Certificate Mapping Failed.