2 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
6 * The contents of this file are subject to the Netscape Public
7 * License Version 1.1 (the "License"); you may not use this file
8 * except in compliance with the License. You may obtain a copy of
9 * the License at http://www.mozilla.org/NPL/
11 * Software distributed under the License is distributed on an "AS
12 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
13 * implied. See the License for the specific language governing
14 * rights and limitations under the License.
16 * The Original Code is Mozilla Communicator client code, released
19 * The Initial Developer of the Original Code is Netscape
20 * Communications Corporation. Portions created by Netscape are
21 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
34 #if defined( _WINDOWS )
36 #include "proto-ntutil.h"
48 #include <solaris-int.h>
53 /* XXX:mhein The following is a workaround for the redefinition of */
54 /* const problem on OSF. Fix to be provided by NSS */
55 /* This is a pretty benign workaround for us which */
56 /* should not cause problems in the future even if */
57 /* we forget to take it out :-) */
66 #define FILE_PATHSEP '/'
73 #define START_TLS_OID "1.3.6.1.4.1.1466.20037"
75 static PRStatus
local_SSLPLCY_Install(void);
78 * This little tricky guy keeps us from initializing twice
80 static int inited
= 0;
82 mutex_t inited_mutex
= DEFAULTMUTEX
;
84 static mutex_t inited_mutex
= DEFAULTMUTEX
;
85 #endif /* _SOLARIS_SDK */
86 #if 0 /* UNNEEDED BY LIBLDAP */
87 static char tokDes
[34] = "Internal (Software) Database ";
88 static char ptokDes
[34] = "Internal (Software) Token ";
89 #endif /* UNNEEDED BY LIBLDAP */
93 /* string: /u/mhein/.netscape/mykey3.db */
95 /* dir: /u/mhein/.netscape/ */
100 splitpath(char *string
, char *dir
, char *prefix
, char *key
) {
111 /* goto the end of the string, and walk backwards until */
112 /* you get to the first pathseparator */
113 len
= PL_strlen(string
);
114 l
= string
+ len
- 1;
115 while (l
!= string
&& *l
!= '/' && *l
!= '\\')
117 /* search for the .db */
118 if ((k
= PL_strstr(l
, ".db")) != NULL
) {
119 /* now we are sitting on . of .db */
121 /* move backward to the first 'c' or 'k' */
122 /* indicating cert or key */
123 while (k
!= l
&& *k
!= 'c' && *k
!= 'k')
126 /* move backwards to the first path separator */
129 while (s
!= d
&& *s
!= '/' && *s
!= '\\')
132 /* if we are sitting on top of a path */
133 /* separator there is no prefix */
135 /* we know there is no prefix */
141 /* grab the prefix */
144 PL_strcpy(prefix
, ++s
);
149 /* neither *key[0-9].db nor *cert[0=9].db found */
157 static PRStatus
local_SSLPLCY_Install(void)
159 return NSS_SetDomesticPolicy() ? PR_FAILURE
: PR_SUCCESS
;
165 ldapssl_basic_init( void )
169 * NSPR is initialized in .init on SOLARIS
171 /* PR_Init() must to be called before everything else... */
172 PR_Init(PR_USER_THREAD
, PR_PRIORITY_NORMAL
, 0);
175 PR_SetConcurrency( 4 ); /* work around for NSPR 3.x I/O hangs */
181 * Cover functions for malloc(), calloc(), strdup() and free() that are
182 * compatible with the NSS libraries (they seem to use the C runtime
183 * library malloc/free so these functions are quite simple right now).
186 ldapssl_malloc( size_t size
)
196 ldapssl_calloc( int nelem
, size_t elsize
)
200 p
= calloc( nelem
, elsize
);
206 ldapssl_strdup( const char *s
)
220 ldapssl_free( void **pp
)
222 if ( NULL
!= pp
&& NULL
!= *pp
) {
231 * Disable strict fork detection of NSS library to allow safe fork of
232 * consumers. Otherwise NSS will not work after fork because it was not
233 * deinitialized before fork and there is no safe way how to do it after fork.
236 * 1 - DISABLED was already set, no modification to environment
237 * 0 - successfully modified environment, old value saved to enval if there
239 * -1 - setenv or strdup failed, the environment was left unchanged
243 update_nss_strict_fork_env(char **enval
)
245 char *temps
= getenv("NSS_STRICT_NOFORK");
248 } else if (strncmp(temps
, "DISABLED", 9) == 0) {
249 /* Do not need to set as DISABLED, it is already set. */
253 if ((*enval
= ldapssl_strdup(temps
)) == NULL
)
256 return (setenv("NSS_STRICT_NOFORK", "DISABLED", 1));
260 * Reset environment variable NSS_STRICT_NOFORK to value before
261 * update_nss_strict_fork_env() call or remove it from environment if it did
263 * NSS_STRICT_NOFORK=DISABLED is needed only during NSS initialization to
264 * disable activation of atfork handler in NSS which is invalidating
265 * initialization in child process after fork.
268 reset_nss_strict_fork_env(char *enval
)
271 return (setenv("NSS_STRICT_NOFORK", enval
, 1));
273 return (unsetenv("NSS_STRICT_NOFORK"));
280 buildDBName(const char *basename
, const char *dbname
)
283 PRUint32 len
, pathlen
, addslash
;
287 if (( len
= PL_strlen( basename
)) > 3
288 && PL_strcasecmp( ".db", basename
+ len
- 3 ) == 0 ) {
289 return (ldapssl_strdup(basename
));
293 len
= pathlen
+ PL_strlen(dbname
) + 1;
294 addslash
= ( pathlen
> 0 &&
295 (( *(basename
+ pathlen
- 1) != FILE_PATHSEP
) ||
296 ( *(basename
+ pathlen
- 1) != '\\' )));
301 if (( result
= ldapssl_malloc( len
)) != NULL
) {
302 PL_strcpy( result
, basename
);
304 *(result
+pathlen
) = FILE_PATHSEP
; /* replaces '\0' */
307 PL_strcpy(result
+pathlen
, dbname
);
317 GetCertDBName(void *alias
, int dbVersion
)
322 source
= (char *)alias
;
329 sprintf(dbname
, "cert%d.db",dbVersion
);
330 return(buildDBName(source
, dbname
));
336 * return database name by appending "dbname" to "path".
337 * this code doesn't need to be terribly efficient (not called often).
339 /* XXXceb this is the old function. To be removed eventually */
341 GetDBName(const char *dbname
, const char *path
)
344 PRUint32 len
, pathlen
;
347 if ( dbname
== NULL
) {
351 if ((path
== NULL
) || (*path
== 0)) {
352 result
= ldapssl_strdup(dbname
);
354 pathlen
= PL_strlen(path
);
355 len
= pathlen
+ PL_strlen(dbname
) + 1;
356 addslash
= ( path
[pathlen
- 1] != '/' );
360 if (( result
= ldapssl_malloc( len
)) != NULL
) {
361 PL_strcpy( result
, path
);
363 *(result
+pathlen
) = '/'; /* replaces '\0' */
366 PL_strcpy(result
+pathlen
, dbname
);
374 * Initialize ns/security so it can be used for SSL client authentication.
375 * It is safe to call this more than once.
377 * If needkeydb == 0, no key database is opened and SSL server authentication
378 * is supported but not client authentication.
380 * If "certdbpath" is NULL or "", the default cert. db is used (typically
381 * ~/.netscape/cert7.db).
383 * If "certdbpath" ends with ".db" (case-insensitive compare), then
384 * it is assumed to be a full path to the cert. db file; otherwise,
385 * it is assumed to be a directory that contains a file called
386 * "cert7.db" or "cert.db".
388 * If certdbhandle is non-NULL, it is assumed to be a pointer to a
389 * SECCertDBHandle structure. It is fine to pass NULL since this
390 * routine will allocate one for you (CERT_GetDefaultDB() can be
391 * used to retrieve the cert db handle).
393 * If "keydbpath" is NULL or "", the default key db is used (typically
394 * ~/.netscape/key3.db).
396 * If "keydbpath" ends with ".db" (case-insensitive compare), then
397 * it is assumed to be a full path to the key db file; otherwise,
398 * it is assumed to be a directory that contains a file called
401 * If certdbhandle is non-NULL< it is assumed to be a pointed to a
402 * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
403 * routine will allocate one for you (SECKEY_GetDefaultDB() can be
404 * used to retrieve the cert db handle).
408 ldapssl_clientauth_init( const char *certdbpath
, void *certdbhandle
,
409 const int needkeydb
, const char *keydbpath
, void *keydbhandle
)
419 * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_clientauth_init\n",0 ,0 ,0);
422 mutex_lock(&inited_mutex
);
424 mutex_unlock(&inited_mutex
);
428 ldapssl_basic_init();
431 if ((rcenv
= update_nss_strict_fork_env(&enval
)) == -1) {
432 mutex_unlock(&inited_mutex
);
437 /* Open the certificate database */
438 rc
= NSS_Init(certdbpath
);
440 /* Error from NSS_Init() more important! */
441 if ((rcenv
!= 1) && (reset_nss_strict_fork_env(enval
) != 0) && (rc
== 0)) {
442 ldapssl_free(&enval
);
443 mutex_unlock(&inited_mutex
);
446 ldapssl_free(&enval
);
449 if ((rc
= PR_GetError()) >= 0)
451 mutex_unlock(&inited_mutex
);
455 if (SSL_OptionSetDefault(SSL_ENABLE_SSL2
, PR_FALSE
)
456 || SSL_OptionSetDefault(SSL_ENABLE_SSL3
, PR_TRUE
)) {
457 if (( rc
= PR_GetError()) >= 0 ) {
460 mutex_unlock(&inited_mutex
);
466 if (local_SSLPLCY_Install() == PR_FAILURE
) {
467 mutex_unlock(&inited_mutex
);
472 mutex_unlock(&inited_mutex
);
479 * Initialize ns/security so it can be used for SSL client authentication.
480 * It is safe to call this more than once.
482 * If needkeydb == 0, no key database is opened and SSL server authentication
483 * is supported but not client authentication.
485 * If "certdbpath" is NULL or "", the default cert. db is used (typically
486 * ~/.netscape/cert7.db).
488 * If "certdbpath" ends with ".db" (case-insensitive compare), then
489 * it is assumed to be a full path to the cert. db file; otherwise,
490 * it is assumed to be a directory that contains a file called
491 * "cert7.db" or "cert.db".
493 * If certdbhandle is non-NULL, it is assumed to be a pointer to a
494 * SECCertDBHandle structure. It is fine to pass NULL since this
495 * routine will allocate one for you (CERT_GetDefaultDB() can be
496 * used to retrieve the cert db handle).
498 * If "keydbpath" is NULL or "", the default key db is used (typically
499 * ~/.netscape/key3.db).
501 * If "keydbpath" ends with ".db" (case-insensitive compare), then
502 * it is assumed to be a full path to the key db file; otherwise,
503 * it is assumed to be a directory that contains a file called
506 * If certdbhandle is non-NULL< it is assumed to be a pointed to a
507 * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
508 * routine will allocate one for you (SECKEY_GetDefaultDB() can be
509 * used to retrieve the cert db handle). */
512 ldapssl_advclientauth_init(
513 const char *certdbpath
, void *certdbhandle
,
514 const int needkeydb
, const char *keydbpath
, void *keydbhandle
,
515 const int needsecmoddb
, const char *secmoddbpath
,
516 const int sslstrength
)
524 mutex_lock(&inited_mutex
);
526 mutex_unlock(&inited_mutex
);
531 * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_advclientauth_init\n",0 ,0 ,0);
534 ldapssl_basic_init();
537 if ((rcenv
= update_nss_strict_fork_env(&enval
)) == -1) {
538 mutex_unlock(&inited_mutex
);
543 rc
= NSS_Init(certdbpath
);
545 /* Error from NSS_Init() more important! */
546 if ((rcenv
!= 1) && (reset_nss_strict_fork_env(enval
) != 0) && (rc
== 0)) {
547 ldapssl_free(&enval
);
548 mutex_unlock(&inited_mutex
);
551 ldapssl_free(&enval
);
554 if ((rc
= PR_GetError()) >= 0)
556 mutex_unlock(&inited_mutex
);
560 if (local_SSLPLCY_Install() == PR_FAILURE
) {
561 mutex_unlock(&inited_mutex
);
566 mutex_unlock(&inited_mutex
);
568 return( ldapssl_set_strength( NULL
, sslstrength
));
574 * Initialize ns/security so it can be used for SSL client authentication.
575 * It is safe to call this more than once.
579 * XXXceb This is a hack until the new IO functions are done.
580 * this function lives in ldapsinit.c
582 void set_using_pkcs_functions( int val
);
586 ldapssl_pkcs_init( const struct ldapssl_pkcs_fns
*pfns
)
589 char *certdbName
, *s
, *keydbpath
;
590 char *certdbPrefix
, *keydbPrefix
;
591 char *confDir
, *keydbName
;
592 static char *secmodname
= "secmod.db";
599 mutex_lock(&inited_mutex
);
601 mutex_unlock(&inited_mutex
);
605 * XXXceb This is a hack until the new IO functions are done.
606 * this function MUST be called before ldap_enable_clienauth.
609 set_using_pkcs_functions( 1 );
612 * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_pkcs_init\n",0 ,0 ,0);
616 ldapssl_basic_init();
618 pfns
->pkcs_getcertpath( NULL
, &s
);
619 confDir
= ldapssl_strdup( s
);
620 certdbPrefix
= ldapssl_strdup( s
);
621 certdbName
= ldapssl_strdup( s
);
623 splitpath(s
, confDir
, certdbPrefix
, certdbName
);
625 pfns
->pkcs_getkeypath( NULL
, &s
);
626 keydbpath
= ldapssl_strdup( s
);
627 keydbPrefix
= ldapssl_strdup( s
);
628 keydbName
= ldapssl_strdup( s
);
630 splitpath(s
, keydbpath
, keydbPrefix
, keydbName
);
633 /* verify confDir == keydbpath and adjust as necessary */
634 ldapssl_free((void **)&certdbName
);
635 ldapssl_free((void **)&keydbName
);
636 ldapssl_free((void **)&keydbpath
);
639 if ((rcenv
= update_nss_strict_fork_env(&enval
)) == -1) {
640 mutex_unlock(&inited_mutex
);
645 rc
= NSS_Initialize(confDir
,certdbPrefix
,keydbPrefix
,secmodname
,
648 ldapssl_free((void **)&certdbPrefix
);
649 ldapssl_free((void **)&keydbPrefix
);
650 ldapssl_free((void **)&confDir
);
653 /* Error from NSS_Initialize() more important! */
654 if ((rcenv
!= 1) && (reset_nss_strict_fork_env(enval
) != 0) && (rc
== 0)) {
655 ldapssl_free(&enval
);
656 mutex_unlock(&inited_mutex
);
659 ldapssl_free(&enval
);
663 if ((rc
= PR_GetError()) >= 0)
665 mutex_unlock(&inited_mutex
);
670 #if 0 /* UNNEEDED BY LIBLDAP */
672 PK11_ConfigurePKCS11(NULL
, NULL
, tokDes
, ptokDes
, NULL
, NULL
, NULL
, NULL
, 0, 0 );
673 #endif /* UNNEEDED BY LIBLDAP */
675 if (SSL_OptionSetDefault(SSL_ENABLE_SSL2
, PR_FALSE
)
676 || SSL_OptionSetDefault(SSL_ENABLE_SSL3
, PR_TRUE
)) {
677 if (( rc
= PR_GetError()) >= 0 ) {
681 mutex_unlock(&inited_mutex
);
685 if (local_SSLPLCY_Install() == PR_FAILURE
) {
686 mutex_unlock(&inited_mutex
);
692 if ( certdbName
!= NULL
) {
693 ldapssl_free((void **) &certdbName
);
696 return( ldapssl_set_strength( NULL
, LDAPSSL_AUTH_CNCHECK
));
701 * ldapssl_client_init() is a server-authentication only version of
702 * ldapssl_clientauth_init().
706 ldapssl_client_init(const char* certdbpath
, void *certdbhandle
)
708 return( ldapssl_clientauth_init( certdbpath
, certdbhandle
,
712 * ldapssl_serverauth_init() is a server-authentication only version of
713 * ldapssl_clientauth_init(). This function allows the sslstrength
714 * to be passed in. The sslstrength can take one of the following
716 * LDAPSSL_AUTH_WEAK: indicate that you accept the server's
717 * certificate without checking the CA who
718 * issued the certificate
719 * LDAPSSL_AUTH_CERT: indicates that you accept the server's
720 * certificate only if you trust the CA who
721 * issued the certificate
722 * LDAPSSL_AUTH_CNCHECK:
723 indicates that you accept the server's
724 * certificate only if you trust the CA who
725 * issued the certificate and if the value
726 * of the cn attribute in the DNS hostname
731 ldapssl_serverauth_init(const char* certdbpath
,
733 const int sslstrength
)
735 if ( ldapssl_set_strength( NULL
, sslstrength
) != 0) {
739 return( ldapssl_clientauth_init( certdbpath
, certdbhandle
,
744 * Function that makes an asynchronous Start TLS extended operation request.
746 static int ldapssl_tls_start(LDAP
*ld
, int *msgidp
)
749 BerValue extreq_data
;
751 /* Start TLS extended operation requires an absent "requestValue" field. */
753 extreq_data
.bv_val
= NULL
;
754 extreq_data
.bv_len
= 0;
756 /* Make sure version is set to LDAPv3 for extended operations to be
759 version
= LDAP_VERSION3
;
760 ldap_set_option( ld
, LDAP_OPT_PROTOCOL_VERSION
, &version
);
762 /* Send the Start TLS request (OID: 1.3.6.1.4.1.1466.20037) */
763 rc
= ldap_extended_operation( ld
, START_TLS_OID
, &extreq_data
,
764 NULL
, NULL
, msgidp
);
771 * Function that enables SSL on an already open non-secured LDAP connection.
772 * (i.e. the connection is henceforth secured)
774 static int ldapssl_enableSSL_on_open_connection(LDAP
*ld
, int defsecure
,
775 char *certdbpath
, char *keydbpath
)
777 PRLDAPSocketInfo soi
;
780 if ( ldapssl_clientauth_init( certdbpath
, NULL
, 1, keydbpath
, NULL
) < 0 ) {
781 goto ssl_setup_failure
;
785 * Retrieve socket info. so we have the PRFileDesc.
787 memset( &soi
, 0, sizeof(soi
));
788 soi
.soinfo_size
= PRLDAP_SOCKETINFO_SIZE
;
789 if ( prldap_get_default_socket_info( ld
, &soi
) < 0 ) {
790 goto ssl_setup_failure
;
793 if ( ldapssl_install_routines( ld
) < 0 ) {
794 goto ssl_setup_failure
;
798 if (soi
.soinfo_prfd
== NULL
) {
800 ldap_get_option( ld
, LDAP_OPT_DESC
, &sd
);
801 soi
.soinfo_prfd
= (PRFileDesc
*) PR_ImportTCPSocket( sd
);
803 /* set the socket information back into the connection handle,
804 * because ldapssl_install_routines() resets the socket_arg info in the
806 if ( prldap_set_default_socket_info( ld
, &soi
) != LDAP_SUCCESS
) {
807 goto ssl_setup_failure
;
810 if ( ldap_set_option( ld
, LDAP_OPT_SSL
,
811 defsecure
? LDAP_OPT_ON
: LDAP_OPT_OFF
) < 0 ) {
812 goto ssl_setup_failure
;
815 if ( ldapssl_import_fd( ld
, defsecure
) < 0 ) {
816 goto ssl_setup_failure
;
822 ldapssl_reset_to_nonsecure( ld
);
824 /* we should here warn the server that we switch back to a non-secure
832 * ldapssl_tls_start_s() performs a synchronous Start TLS extended operation
835 * The function returns the result code of the extended operation response
836 * sent by the server.
838 * In case of a successfull response (LDAP_SUCCESS returned), by the time
839 * this function returns the LDAP session designed by ld will have been
840 * secured, i.e. the connection will have been imported into SSL.
842 * Should the Start TLS request be rejected by the server, the result code
843 * returned will be one of the following:
844 * LDAP_OPERATIONS_ERROR,
845 * LDAP_PROTOCOL_ERROR,
849 * Any other error code returned will be due to a failure in the course
850 * of operations done on the client side.
852 * "certdbpath" and "keydbpath" should contain the path to the client's
853 * certificate and key databases respectively. Either the path to the
854 * directory containing "default name" databases (i.e. cert7.db and key3.db)
855 * can be specified or the actual filenames can be included.
856 * If any of these parameters is NULL, the function will assume the database
857 * is the same used by Netscape Communicator, which is usually under
860 * "referralsp" is a pointer to a list of referrals the server might
861 * eventually send back with an LDAP_REFERRAL result code.
867 ldapssl_tls_start_s(LDAP
*ld
,int defsecure
, char *certdbpath
, char *keydbpath
,
870 int rc
, resultCode
, msgid
;
872 BerValue
*extresp_data
;
875 rc
= ldapssl_tls_start( ld
, &msgid
);
876 if ( rc
!= LDAP_SUCCESS
) {
880 rc
= ldap_result( ld
, msgid
, 1, NULL
, &res
);
881 if ( rc
!= LDAP_RES_EXTENDED
) {
883 /* the first response received must be an extended response to an
891 rc
= ldap_parse_extended_result( ld
, res
, &extresp_oid
, &extresp_data
, 0 );
893 if ( rc
!= LDAP_SUCCESS
) {
898 if ( strcasecmp( extresp_oid
, START_TLS_OID
) != 0 ) {
900 /* the extended response received doesn't correspond to the
907 resultCode
= ldap_get_lderrno( ld
, NULL
, NULL
);
909 /* Analyze the server's response */
910 switch (resultCode
) {
913 rc
= ldap_parse_result( ld
, res
, NULL
, NULL
, NULL
, referralsp
, NULL
, 0 );
914 if ( rc
!= LDAP_SUCCESS
) {
919 case LDAP_OPERATIONS_ERROR
:
921 case LDAP_PROTOCOL_ERROR
:
923 case LDAP_UNAVAILABLE
:
924 goto free_msg_and_return
;
928 * If extended response successfull, get connection ready for
929 * communicating with the server over SSL/TLS.
932 if ( ldapssl_enableSSL_on_open_connection( ld
, defsecure
,
933 certdbpath
, keydbpath
) < 0 ) {
937 } /* case LDAP_SUCCESS */
939 goto free_msg_and_return
;