Back to index

lightning-sunbird  0.9+nobinonly
clientinit.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * clientinit.c
00040  */
00041 
00042 #if defined(NET_SSL)
00043 
00044 
00045 #if defined( _WINDOWS )
00046 #include <windows.h>
00047 #include "proto-ntutil.h"
00048 #endif
00049 
00050 #include <nspr.h>
00051 #include <plstr.h>
00052 #include <cert.h>
00053 #include <key.h>
00054 #include <ssl.h>
00055 #include <sslproto.h>
00056 #include <ldap.h>
00057 #include <ldap_ssl.h>
00058 #include <nss.h>
00059 
00060 /* XXX:mhein The following is a workaround for the redefinition of */
00061 /*          const problem on OSF.  Fix to be provided by NSS */
00062 /*          This is a pretty benign workaround for us which */
00063 /*          should not cause problems in the future even if */
00064 /*          we forget to take it out :-) */
00065 
00066 #ifdef OSF1V4D
00067 #ifndef __STDC__
00068 #  define __STDC__
00069 #endif /* __STDC__ */
00070 #endif /* OSF1V4D */
00071 
00072 #ifndef FILE_PATHSEP
00073 #define FILE_PATHSEP '/'
00074 #endif
00075 
00076 
00077 static PRStatus local_SSLPLCY_Install(void);
00078 
00079 /*
00080  * This little tricky guy keeps us from initializing twice 
00081  */
00082 static int           inited = 0;
00083 static int ssl_strength = LDAPSSL_AUTH_CERT;
00084 static char  tokDes[34] = "Internal (Software) Database     ";
00085 static char ptokDes[34] = "Internal (Software) Token        ";
00086 
00087 
00088 /* IN:                                  */
00089 /* string:    /u/mhein/.netscape/mykey3.db */
00090 /* OUT:                                        */
00091 /* dir:       /u/mhein/.netscape/       */
00092 /* prefix:    my                        */
00093 /* key:              key3.db                          */
00094 
00095 static int
00096 splitpath(char *string, char *dir, char *prefix, char *key) {
00097         char *k;
00098         char *s;
00099         char *d = string;
00100         char *l;
00101         int  len = 0;
00102 
00103 
00104         if (string == NULL)
00105                 return (-1);
00106 
00107         /* goto the end of the string, and walk backwards until */
00108         /* you get to the first pathseparator */
00109         len = PL_strlen(string);
00110         l = string + len - 1;
00111         while (l != string && *l != '/' && *l != '\\')
00112                         l--;
00113         /* search for the .db */
00114         if ((k = PL_strstr(l, ".db")) != NULL) {
00115                 /* now we are sitting on . of .db */
00116 
00117                 /* move backward to the first 'c' or 'k' */
00118                 /* indicating cert or key */
00119                 while (k != l && *k != 'c' && *k != 'k')
00120                         k--;
00121 
00122                 /* move backwards to the first path separator */
00123                 if (k != d && k > d)
00124                         s = k - 1;
00125                 while (s != d && *s != '/' && *s != '\\')
00126                         s--;
00127 
00128                 /* if we are sitting on top of a path */
00129                 /* separator there is no prefix */
00130                 if (s + 1 == k) {
00131                         /* we know there is no prefix */
00132                         prefix = '\0';
00133                         PL_strcpy(key, k);
00134                         *k = '\0';
00135                         PL_strcpy(dir, d);
00136                 } else {
00137                         /* grab the prefix */
00138                         PL_strcpy(key, k);
00139                         *k = '\0';
00140                         PL_strcpy(prefix, ++s);
00141                         *s = '\0';
00142                         PL_strcpy(dir, d);
00143                 }
00144         } else {
00145                 /* neither *key[0-9].db nor *cert[0=9].db found */
00146                 return (-1);
00147         }
00148 
00149        return (0);
00150 }
00151 
00152 
00153 static PRStatus local_SSLPLCY_Install(void)
00154 {
00155        SECStatus s;
00156 
00157 #ifdef NS_DOMESTIC
00158        s = NSS_SetDomesticPolicy(); 
00159 #elif NS_EXPORT
00160        s = NSS_SetExportPolicy(); 
00161 #else
00162        s = PR_FAILURE;
00163 #endif
00164        return s?PR_FAILURE:PR_SUCCESS;
00165 }
00166 
00167 
00168 
00169 static void
00170 ldapssl_basic_init( void )
00171 {
00172     /* PR_Init() must to be called before everything else... */
00173     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
00174 
00175     PR_SetConcurrency( 4 ); /* work around for NSPR 3.x I/O hangs */
00176 }
00177 
00178 
00179 
00180 /*
00181  * Cover  functions for malloc(), calloc(), strdup() and free() that are
00182  * compatible with the NSS libraries (they seem to use the C runtime
00183  * library malloc/free so these functions are quite simple right now).
00184  */
00185 static void *
00186 ldapssl_malloc( size_t size )
00187 {
00188     void      *p;
00189 
00190     p = malloc( size );
00191     return p;
00192 }
00193 
00194 
00195 static void *
00196 ldapssl_calloc( int nelem, size_t elsize )
00197 {
00198     void      *p;
00199 
00200     p = calloc( nelem, elsize );
00201     return p;
00202 }
00203 
00204 
00205 static char *
00206 ldapssl_strdup( const char *s )
00207 {
00208     char      *scopy;
00209 
00210     if ( NULL == s ) {
00211        scopy = NULL;
00212     } else {
00213        scopy = strdup( s );
00214     }
00215     return scopy;
00216 }
00217 
00218 
00219 static void
00220 ldapssl_free( void **pp )
00221 {
00222     if ( NULL != pp && NULL != *pp ) {
00223        free( (void *)*pp );
00224        *pp = NULL;
00225     }
00226 }
00227 
00228 
00229 static char *
00230 buildDBName(const char *basename, const char *dbname)
00231 {
00232        char          *result;
00233        PRUint32      len, pathlen, addslash;
00234 
00235        if (basename)
00236        {
00237            if (( len = PL_strlen( basename )) > 3
00238               && PL_strcasecmp( ".db", basename + len - 3 ) == 0 ) {
00239               return (ldapssl_strdup(basename));
00240            }
00241            
00242            pathlen = len;
00243            len = pathlen + PL_strlen(dbname) + 1;
00244            addslash = ( pathlen > 0 &&
00245               (( *(basename + pathlen - 1) != FILE_PATHSEP ) || 
00246               ( *(basename + pathlen - 1) != '\\'  )));
00247 
00248            if ( addslash ) {
00249               ++len;
00250            }
00251            if (( result = ldapssl_malloc( len )) != NULL ) {
00252               PL_strcpy( result, basename );
00253               if ( addslash ) {
00254                   *(result+pathlen) = FILE_PATHSEP;  /* replaces '\0' */
00255                   ++pathlen;
00256               }
00257               PL_strcpy(result+pathlen, dbname);
00258            }
00259            
00260        }
00261 
00262 
00263        return result;
00264 }
00265 
00266 char *
00267 GetCertDBName(void *alias, int dbVersion)
00268 {
00269     char             *source;
00270     char dbname[128];
00271     
00272     source = (char *)alias;
00273     
00274     if (!source)
00275     {
00276        source = "";
00277     }
00278     
00279     sprintf(dbname, "cert%d.db",dbVersion);
00280     return(buildDBName(source, dbname));
00281 
00282 
00283 }
00284 
00285 /*
00286  * return database name by appending "dbname" to "path".
00287  * this code doesn't need to be terribly efficient (not called often).
00288  */
00289 /* XXXceb this is the old function.  To be removed eventually */
00290 static char *
00291 GetDBName(const char *dbname, const char *path)
00292 {
00293     char             *result;
00294     PRUint32  len, pathlen;
00295     int              addslash;
00296     
00297     if ( dbname == NULL ) {
00298        dbname = "";
00299     }
00300     
00301     if ((path == NULL) || (*path == 0)) {
00302        result = ldapssl_strdup(dbname);
00303     } else {
00304        pathlen = PL_strlen(path);
00305        len = pathlen + PL_strlen(dbname) + 1;
00306        addslash = ( path[pathlen - 1] != '/' );
00307        if ( addslash ) {
00308            ++len;
00309        }
00310        if (( result = ldapssl_malloc( len )) != NULL ) {
00311            PL_strcpy( result, path );
00312            if ( addslash ) {
00313               *(result+pathlen) = '/';  /* replaces '\0' */
00314               ++pathlen;
00315            }
00316            PL_strcpy(result+pathlen, dbname);
00317        }
00318     }
00319     
00320     return result;
00321 }
00322 
00323 /*
00324  * Initialize ns/security so it can be used for SSL client authentication.
00325  * It is safe to call this more than once.
00326  *
00327  * If needkeydb == 0, no key database is opened and SSL server authentication
00328  * is supported but not client authentication.
00329  *
00330  * If "certdbpath" is NULL or "", the default cert. db is used (typically
00331  * ~/.netscape/cert7.db).
00332  *
00333  * If "certdbpath" ends with ".db" (case-insensitive compare), then
00334  * it is assumed to be a full path to the cert. db file; otherwise,
00335  * it is assumed to be a directory that contains a file called
00336  * "cert7.db" or "cert.db".
00337  *
00338  * If certdbhandle is non-NULL, it is assumed to be a pointer to a
00339  * SECCertDBHandle structure.  It is fine to pass NULL since this
00340  * routine will allocate one for you (CERT_GetDefaultDB() can be
00341  * used to retrieve the cert db handle).
00342  *
00343  * If "keydbpath" is NULL or "", the default key db is used (typically
00344  * ~/.netscape/key3.db).
00345  *
00346  * If "keydbpath" ends with ".db" (case-insensitive compare), then
00347  * it is assumed to be a full path to the key db file; otherwise,
00348  * it is assumed to be a directory that contains a file called
00349  * "key3.db" 
00350  *
00351  * If certdbhandle is non-NULL< it is assumed to be a pointed to a
00352  * SECKEYKeyDBHandle structure.  It is fine to pass NULL since this
00353  * routine will allocate one for you (SECKEY_GetDefaultDB() can be
00354  * used to retrieve the cert db handle).
00355  */
00356 int
00357 LDAP_CALL
00358 ldapssl_clientauth_init( const char *certdbpath, void *certdbhandle, 
00359     const int needkeydb, const char *keydbpath, void *keydbhandle )
00360 
00361 {
00362 
00363     int       rc;
00364      
00365     /*
00366      *     LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_clientauth_init\n",0 ,0 ,0);
00367      */
00368 
00369     if ( inited ) {
00370        return( 0 );
00371     }
00372 
00373     ldapssl_basic_init();
00374 
00375 
00376     /* Open the certificate database */
00377     if ((rc = NSS_Init(certdbpath)) != SECSuccess) {
00378        return (-1);
00379     }
00380 
00381     if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
00382            || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
00383        if (( rc = PR_GetError()) >= 0 ) {
00384            rc = -1;
00385        }
00386        return( rc );
00387     }
00388 
00389 
00390 
00391 #if defined(NS_DOMESTIC)
00392     if (local_SSLPLCY_Install() == PR_FAILURE)
00393       return( -1 );
00394 #elif(NS_EXPORT)
00395     if (local_SSLPLCY_Install() == PR_FAILURE)
00396       return( -1 );
00397 #else
00398     return( -1 );
00399 #endif
00400 
00401     inited = 1;
00402 
00403     return( 0 );
00404 
00405 }
00406 
00407 
00408 /* 
00409  * This is not the most elegant solution to SSL strength, but it
00410  * works because ldapssl_advclientauth_init() is only called once.
00411  */
00412 
00413 int get_ssl_strength( void )
00414 {
00415   return ssl_strength;
00416 }
00417 
00418 /* 
00419  * At some point we might want to consider protecting this 
00420  * with a mutex..  For now there is no need.
00421  */
00422 int set_ssl_strength(int strength_val)
00423 {
00424 
00425   if (strength_val == LDAPSSL_AUTH_WEAK ||
00426       strength_val == LDAPSSL_AUTH_CERT ||
00427       strength_val == LDAPSSL_AUTH_CNCHECK ) {
00428     ssl_strength = strength_val;
00429     return LDAP_SUCCESS;
00430   }
00431   return LDAP_PARAM_ERROR;
00432 
00433 }
00434 
00435 
00436 
00437 /*
00438  * Initialize ns/security so it can be used for SSL client authentication.
00439  * It is safe to call this more than once.
00440  *
00441  * If needkeydb == 0, no key database is opened and SSL server authentication
00442  * is supported but not client authentication.
00443  *
00444  * If "certdbpath" is NULL or "", the default cert. db is used (typically
00445  * ~/.netscape/cert7.db).
00446  *
00447  * If "certdbpath" ends with ".db" (case-insensitive compare), then
00448  * it is assumed to be a full path to the cert. db file; otherwise,
00449  * it is assumed to be a directory that contains a file called
00450  * "cert7.db" or "cert.db".
00451  *
00452  * If certdbhandle is non-NULL, it is assumed to be a pointer to a
00453  * SECCertDBHandle structure.  It is fine to pass NULL since this
00454  * routine will allocate one for you (CERT_GetDefaultDB() can be
00455  * used to retrieve the cert db handle).
00456  *
00457  * If "keydbpath" is NULL or "", the default key db is used (typically
00458  * ~/.netscape/key3.db).
00459  *
00460  * If "keydbpath" ends with ".db" (case-insensitive compare), then
00461  * it is assumed to be a full path to the key db file; otherwise,
00462  * it is assumed to be a directory that contains a file called
00463  * "key3.db" 
00464  *
00465  * If certdbhandle is non-NULL< it is assumed to be a pointed to a
00466  * SECKEYKeyDBHandle structure.  It is fine to pass NULL since this
00467  * routine will allocate one for you (SECKEY_GetDefaultDB() can be
00468  * used to retrieve the cert db handle).  */
00469 int
00470 LDAP_CALL
00471 ldapssl_advclientauth_init( 
00472     const char *certdbpath, void *certdbhandle, 
00473     const int needkeydb, const char *keydbpath, void *keydbhandle,  
00474     const int needsecmoddb, const char *secmoddbpath,
00475     const int sslstrength )
00476 {
00477     int rc = 0;
00478 
00479     if ( inited ) {
00480        return( 0 );
00481     }
00482 
00483     /*
00484      *    LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_advclientauth_init\n",0 ,0 ,0);
00485      */
00486 
00487     ldapssl_basic_init();
00488 
00489     if ((rc = NSS_Init(certdbpath)) != SECSuccess) {
00490        return (-1);
00491     }
00492 
00493 #if defined(NS_DOMESTIC)
00494     if (local_SSLPLCY_Install() == PR_FAILURE)
00495       return( -1 );
00496 #elif(NS_EXPORT)
00497     if (local_SSLPLCY_Install() == PR_FAILURE)
00498       return( -1 );
00499 #else
00500     return( -1 );
00501 #endif
00502 
00503     inited = 1;
00504     
00505     set_ssl_strength( sslstrength );
00506 
00507     return( 0 );
00508 
00509 }
00510 
00511 
00512 /*
00513  * Initialize ns/security so it can be used for SSL client authentication.
00514  * It is safe to call this more than once.
00515   */
00516 
00517 /* 
00518  * XXXceb  This is a hack until the new IO functions are done.
00519  * this function lives in ldapsinit.c
00520  */
00521 void set_using_pkcs_functions( int val );
00522 
00523 int
00524 LDAP_CALL
00525 ldapssl_pkcs_init( const struct ldapssl_pkcs_fns *pfns )
00526 {
00527 
00528     char             *certdbName, *s, *keydbpath;
00529     char             *certdbPrefix, *keydbPrefix;
00530     char             *confDir, *keydbName;
00531     static char         *secmodname =  "secmod.db";
00532     int                     rc;
00533     
00534     if ( inited ) {
00535        return( 0 );
00536     }
00537 /* 
00538  * XXXceb  This is a hack until the new IO functions are done.
00539  * this function MUST be called before ldapssl_enable_clientauth.
00540  * 
00541  */
00542     set_using_pkcs_functions( 1 );
00543     
00544     /*
00545      *    LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_pkcs_init\n",0 ,0 ,0);
00546      */
00547 
00548 
00549     ldapssl_basic_init();
00550 
00551     pfns->pkcs_getcertpath( NULL, &s);
00552     confDir = ldapssl_strdup( s );
00553     certdbPrefix = ldapssl_strdup( s );
00554     certdbName = ldapssl_strdup( s );
00555     *certdbPrefix = 0;
00556     splitpath(s, confDir, certdbPrefix, certdbName);
00557 
00558     pfns->pkcs_getkeypath( NULL, &s);
00559     keydbpath = ldapssl_strdup( s );
00560     keydbPrefix = ldapssl_strdup( s );
00561     keydbName = ldapssl_strdup( s );
00562     *keydbPrefix = 0;
00563     splitpath(s, keydbpath, keydbPrefix, keydbName);
00564 
00565 
00566     /* verify confDir == keydbpath and adjust as necessary */
00567     ldapssl_free((void **)&certdbName);
00568     ldapssl_free((void **)&keydbName);
00569     ldapssl_free((void **)&keydbpath);
00570 
00571     if ((rc = NSS_Initialize(confDir,certdbPrefix,keydbPrefix,
00572               secmodname, NSS_INIT_READONLY)) != SECSuccess) {
00573        return (-1);
00574     }
00575 
00576     ldapssl_free((void **)&certdbPrefix);
00577     ldapssl_free((void **)&keydbPrefix);
00578     ldapssl_free((void **)&confDir);
00579     
00580 
00581     /* this is odd */
00582     PK11_ConfigurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
00583 
00584     if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
00585        || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
00586        if (( rc = PR_GetError()) >= 0 ) {
00587            rc = -1;
00588        }
00589        
00590        return( rc );
00591     }
00592     
00593 #if defined(NS_DOMESTIC)
00594     if (local_SSLPLCY_Install() == PR_FAILURE)
00595       return( -1 );
00596 #elif(NS_EXPORT)
00597     if (local_SSLPLCY_Install() == PR_FAILURE)
00598       return( -1 );
00599 #else
00600     return( -1 );
00601 #endif
00602 
00603     inited = 1;
00604 
00605     if ( certdbName != NULL ) {
00606        ldapssl_free((void **) &certdbName );
00607     }
00608     
00609     /*
00610     set_ssl_strength( sslstrength );
00611     */
00612 
00613     set_ssl_strength( LDAPSSL_AUTH_CERT );
00614     return( 0 );
00615 }
00616 
00617 
00618 /*
00619  * ldapssl_client_init() is a server-authentication only version of
00620  * ldapssl_clientauth_init().
00621  */
00622 int
00623 LDAP_CALL
00624 ldapssl_client_init(const char* certdbpath, void *certdbhandle )
00625 {
00626     return( ldapssl_clientauth_init( certdbpath, certdbhandle,
00627            0, NULL, NULL ));
00628 }
00629 
00630 
00631 /*
00632  * ldapssl_serverauth_init() is a server-authentication only version of
00633  * ldapssl_clientauth_init().  This function allows the sslstrength
00634  * to be passed in.  The sslstrength can take one of the following
00635  * values:
00636  *     LDAPSSL_AUTH_WEAK: indicate that you accept the server's
00637  *                      certificate without checking the CA who
00638  *                      issued the certificate
00639  *     LDAPSSL_AUTH_CERT: indicates that you accept the server's
00640  *                      certificate only if you trust the CA who
00641  *                      issued the certificate
00642  *     LDAPSSL_AUTH_CNCHECK:
00643                         indicates that you accept the server's
00644  *                      certificate only if you trust the CA who
00645  *                      issued the certificate and if the value
00646  *                      of the cn attribute in the DNS hostname
00647  *                      of the server
00648  */
00649 int
00650 LDAP_CALL
00651 ldapssl_serverauth_init(const char* certdbpath,
00652                    void *certdbhandle,
00653                    const int sslstrength )
00654 {
00655     int       rc = LDAP_SUCCESS;
00656 
00657     if ((rc = set_ssl_strength( sslstrength )) != LDAP_SUCCESS) {
00658        return ( rc );
00659     }
00660 
00661     return( ldapssl_clientauth_init( certdbpath, certdbhandle,
00662            0, NULL, NULL ));
00663 }
00664 
00665 #endif /* NET_SSL */