Back to index

openldap  2.4.31
tls_m.c
Go to the documentation of this file.
00001 /* tls_m.c - Handle tls/ssl using Mozilla NSS. */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2008-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS: Initial version written by Howard Chu. 
00017  * Additional support by Rich Megginson.
00018  */
00019 
00020 #include "portable.h"
00021 
00022 #ifdef HAVE_MOZNSS
00023 
00024 #include "ldap_config.h"
00025 
00026 #include <stdio.h>
00027 
00028 #if defined( HAVE_FCNTL_H )
00029 #include <fcntl.h>
00030 #endif
00031 
00032 #include <ac/stdlib.h>
00033 #include <ac/errno.h>
00034 #include <ac/socket.h>
00035 #include <ac/string.h>
00036 #include <ac/ctype.h>
00037 #include <ac/time.h>
00038 #include <ac/unistd.h>
00039 #include <ac/param.h>
00040 #include <ac/dirent.h>
00041 
00042 #include "ldap-int.h"
00043 #include "ldap-tls.h"
00044 
00045 #define READ_PASSWORD_FROM_STDIN
00046 #define READ_PASSWORD_FROM_FILE
00047 
00048 #ifdef READ_PASSWORD_FROM_STDIN
00049 #include <termios.h> /* for echo on/off */
00050 #endif
00051 
00052 #include <nspr/nspr.h>
00053 #include <nspr/private/pprio.h>
00054 #include <nss/nss.h>
00055 #include <nss/ssl.h>
00056 #include <nss/sslerr.h>
00057 #include <nss/sslproto.h>
00058 #include <nss/pk11pub.h>
00059 #include <nss/secerr.h>
00060 #include <nss/keyhi.h>
00061 #include <nss/secmod.h>
00062 #include <nss/cert.h>
00063 
00064 #undef NSS_VERSION_INT
00065 #define       NSS_VERSION_INT      ((NSS_VMAJOR << 24) | (NSS_VMINOR << 16) | \
00066        (NSS_VPATCH << 8) | NSS_VBUILD)
00067 
00068 /* NSS 3.12.5 and later have NSS_InitContext */
00069 #if NSS_VERSION_INT >= 0x030c0500
00070 #define HAVE_NSS_INITCONTEXT 1
00071 #endif
00072 
00073 /* NSS 3.12.9 and later have SECMOD_RestartModules */
00074 #if NSS_VERSION_INT >= 0x030c0900
00075 #define HAVE_SECMOD_RESTARTMODULES 1
00076 #endif
00077 
00078 /* InitContext does not currently work in server mode */
00079 /* #define INITCONTEXT_HACK 1 */
00080 
00081 typedef struct tlsm_ctx {
00082        PRFileDesc *tc_model;
00083        int tc_refcnt;
00084        PRBool tc_verify_cert;
00085        CERTCertDBHandle *tc_certdb;
00086        char *tc_certname;
00087        char *tc_pin_file;
00088        struct ldaptls *tc_config;
00089        int tc_is_server;
00090        int tc_require_cert;
00091        PRCallOnceType tc_callonce;
00092        PRBool tc_using_pem;
00093        char *tc_slotname; /* if using pem */
00094 #ifdef HAVE_NSS_INITCONTEXT
00095        NSSInitContext *tc_initctx; /* the NSS context */
00096 #endif
00097        PK11GenericObject **tc_pem_objs; /* array of objects to free */
00098        int tc_n_pem_objs; /* number of objects */
00099        PRBool tc_warn_only; /* only warn of errors in validation */
00100 #ifdef LDAP_R_COMPILE
00101        ldap_pvt_thread_mutex_t tc_refmutex;
00102 #endif
00103 } tlsm_ctx;
00104 
00105 typedef PRFileDesc tlsm_session;
00106 
00107 static PRDescIdentity       tlsm_layer_id;
00108 
00109 static const PRIOMethods tlsm_PR_methods;
00110 
00111 #define PEM_LIBRARY  "nsspem"
00112 #define PEM_MODULE   "PEM"
00113 /* hash files for use with cacertdir have this file name suffix */
00114 #define PEM_CA_HASH_FILE_SUFFIX    ".0"
00115 #define PEM_CA_HASH_FILE_SUFFIX_LEN 2
00116 
00117 static SECMODModule *pem_module;
00118 
00119 #define DEFAULT_TOKEN_NAME "default"
00120 /* sprintf format used to create token name */
00121 #define TLSM_PEM_TOKEN_FMT "PEM Token #%ld"
00122 
00123 static int tlsm_slot_count;
00124 
00125 #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
00126                 (x)->pValue=(v); (x)->ulValueLen = (l);
00127 
00128 /* forward declaration */
00129 static int tlsm_init( void );
00130 
00131 #ifdef LDAP_R_COMPILE
00132 
00133 /* it doesn't seem guaranteed that a client will call
00134    tlsm_thr_init in a non-threaded context - so we have
00135    to wrap the mutex creation in a prcallonce
00136 */
00137 static ldap_pvt_thread_mutex_t tlsm_init_mutex;
00138 static ldap_pvt_thread_mutex_t tlsm_pem_mutex;
00139 static PRCallOnceType tlsm_init_mutex_callonce = {0,0};
00140 
00141 static PRStatus PR_CALLBACK
00142 tlsm_thr_init_callonce( void )
00143 {
00144        if ( ldap_pvt_thread_mutex_init( &tlsm_init_mutex ) ) {
00145               Debug( LDAP_DEBUG_ANY,
00146                         "TLS: could not create mutex for moznss initialization: %d\n", errno, 0, 0 );
00147               return PR_FAILURE;
00148        }
00149 
00150        if ( ldap_pvt_thread_mutex_init( &tlsm_pem_mutex ) ) {
00151               Debug( LDAP_DEBUG_ANY,
00152                         "TLS: could not create mutex for PEM module: %d\n", errno, 0, 0 );
00153               return PR_FAILURE;
00154        }
00155 
00156        return PR_SUCCESS;
00157 }
00158 
00159 static void
00160 tlsm_thr_init( void )
00161 {
00162     ( void )PR_CallOnce( &tlsm_init_mutex_callonce, tlsm_thr_init_callonce );
00163 }
00164 
00165 #endif /* LDAP_R_COMPILE */
00166 
00167 static const char *
00168 tlsm_dump_cipher_info(PRFileDesc *fd)
00169 {
00170        PRUint16 ii;
00171 
00172        for (ii = 0; ii < SSL_NumImplementedCiphers; ++ii) {
00173               PRInt32 cipher = (PRInt32)SSL_ImplementedCiphers[ii];
00174               PRBool enabled = PR_FALSE;
00175               PRInt32 policy = 0;
00176               SSLCipherSuiteInfo info;
00177 
00178               if (fd) {
00179                      SSL_CipherPrefGet(fd, cipher, &enabled);
00180               } else {
00181                      SSL_CipherPrefGetDefault(cipher, &enabled);
00182               }
00183               SSL_CipherPolicyGet(cipher, &policy);
00184               SSL_GetCipherSuiteInfo(cipher, &info, (PRUintn)sizeof(info));
00185               Debug( LDAP_DEBUG_TRACE,
00186                         "TLS: cipher: %d - %s, enabled: %d, ",
00187                         info.cipherSuite, info.cipherSuiteName, enabled );
00188               Debug( LDAP_DEBUG_TRACE,
00189                         "policy: %d\n", policy, 0, 0 );
00190        }
00191 
00192        return "";
00193 }
00194 
00195 /* Cipher definitions */
00196 typedef struct {
00197        char *ossl_name;    /* The OpenSSL cipher name */
00198        int num;            /* The cipher id */
00199        int attr;           /* cipher attributes: algorithms, etc */
00200        int version;        /* protocol version valid for this cipher */
00201        int bits;           /* bits of strength */
00202        int alg_bits;       /* bits of the algorithm */
00203        int strength;       /* LOW, MEDIUM, HIGH */
00204        int enabled;        /* Enabled by default? */
00205 } cipher_properties;
00206 
00207 /* cipher attributes  */
00208 #define SSL_kRSA  0x00000001L
00209 #define SSL_aRSA  0x00000002L
00210 #define SSL_aDSS  0x00000004L
00211 #define SSL_DSS   SSL_aDSS
00212 #define SSL_eNULL 0x00000008L
00213 #define SSL_DES   0x00000010L
00214 #define SSL_3DES  0x00000020L
00215 #define SSL_RC4   0x00000040L
00216 #define SSL_RC2   0x00000080L
00217 #define SSL_AES   0x00000100L
00218 #define SSL_MD5   0x00000200L
00219 #define SSL_SHA1  0x00000400L
00220 #define SSL_SHA   SSL_SHA1
00221 #define SSL_RSA   (SSL_kRSA|SSL_aRSA)
00222 
00223 /* cipher strength */
00224 #define SSL_NULL      0x00000001L
00225 #define SSL_EXPORT40  0x00000002L
00226 #define SSL_EXPORT56  0x00000004L
00227 #define SSL_LOW       0x00000008L
00228 #define SSL_MEDIUM    0x00000010L
00229 #define SSL_HIGH      0x00000020L
00230 
00231 #define SSL2  0x00000001L
00232 #define SSL3  0x00000002L
00233 /* OpenSSL treats SSL3 and TLSv1 the same */
00234 #define TLS1  SSL3
00235 
00236 /* Cipher translation */
00237 static cipher_properties ciphers_def[] = {
00238        /* SSL 2 ciphers */
00239        {"DES-CBC3-MD5", SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_MD5, SSL2, 168, 168, SSL_HIGH, SSL_ALLOWED},
00240        {"RC2-CBC-MD5", SSL_EN_RC2_128_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5, SSL2, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
00241        {"RC4-MD5", SSL_EN_RC4_128_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL2, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
00242        {"DES-CBC-MD5", SSL_EN_DES_64_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_DES|SSL_MD5, SSL2, 56, 56, SSL_LOW, SSL_ALLOWED},
00243        {"EXP-RC2-CBC-MD5", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5, SSL2, 40, 128, SSL_EXPORT40, SSL_ALLOWED},
00244        {"EXP-RC4-MD5", SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL2, 40, 128, SSL_EXPORT40, SSL_ALLOWED},
00245 
00246        /* SSL3 ciphers */
00247        {"RC4-MD5", SSL_RSA_WITH_RC4_128_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL3, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
00248        {"RC4-SHA", SSL_RSA_WITH_RC4_128_SHA, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA1, SSL3, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
00249        {"DES-CBC3-SHA", SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_SHA1, SSL3, 168, 168, SSL_HIGH, SSL_ALLOWED},
00250        {"DES-CBC-SHA", SSL_RSA_WITH_DES_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, SSL3, 56, 56, SSL_LOW, SSL_ALLOWED},
00251        {"EXP-RC4-MD5", SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL3, 40, 128, SSL_EXPORT40, SSL_ALLOWED},
00252        {"EXP-RC2-CBC-MD5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5, SSL3, 0, 0, SSL_EXPORT40, SSL_ALLOWED},
00253        {"NULL-MD5", SSL_RSA_WITH_NULL_MD5, SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_MD5, SSL3, 0, 0, SSL_NULL, SSL_NOT_ALLOWED},
00254        {"NULL-SHA", SSL_RSA_WITH_NULL_SHA, SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_SHA1, SSL3, 0, 0, SSL_NULL, SSL_NOT_ALLOWED},
00255 
00256        /* TLSv1 ciphers */
00257        {"EXP1024-DES-CBC-SHA", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA, TLS1, 56, 56, SSL_EXPORT56, SSL_ALLOWED},
00258        {"EXP1024-RC4-SHA", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA, TLS1, 56, 56, SSL_EXPORT56, SSL_ALLOWED},
00259        {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA, TLS1, 128, 128, SSL_HIGH, SSL_ALLOWED},
00260        {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA, TLS1, 256, 256, SSL_HIGH, SSL_ALLOWED},
00261 };
00262 
00263 #define ciphernum (sizeof(ciphers_def)/sizeof(cipher_properties))
00264 
00265 /* given err which is the current errno, calls PR_SetError with
00266    the corresponding NSPR error code */
00267 static void 
00268 tlsm_map_error(int err)
00269 {
00270        PRErrorCode prError;
00271 
00272        switch ( err ) {
00273        case EACCES:
00274               prError = PR_NO_ACCESS_RIGHTS_ERROR;
00275               break;
00276        case EADDRINUSE:
00277               prError = PR_ADDRESS_IN_USE_ERROR;
00278               break;
00279        case EADDRNOTAVAIL:
00280               prError = PR_ADDRESS_NOT_AVAILABLE_ERROR;
00281               break;
00282        case EAFNOSUPPORT:
00283               prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
00284               break;
00285        case EAGAIN:
00286               prError = PR_WOULD_BLOCK_ERROR;
00287               break;
00288        /*
00289         * On QNX and Neutrino, EALREADY is defined as EBUSY.
00290         */
00291 #if EALREADY != EBUSY
00292        case EALREADY:
00293               prError = PR_ALREADY_INITIATED_ERROR;
00294               break;
00295 #endif
00296        case EBADF:
00297               prError = PR_BAD_DESCRIPTOR_ERROR;
00298               break;
00299 #ifdef EBADMSG
00300        case EBADMSG:
00301               prError = PR_IO_ERROR;
00302               break;
00303 #endif
00304        case EBUSY:
00305               prError = PR_FILESYSTEM_MOUNTED_ERROR;
00306               break;
00307        case ECONNABORTED:
00308               prError = PR_CONNECT_ABORTED_ERROR;
00309               break;
00310        case ECONNREFUSED:
00311               prError = PR_CONNECT_REFUSED_ERROR;
00312               break;
00313        case ECONNRESET:
00314               prError = PR_CONNECT_RESET_ERROR;
00315               break;
00316        case EDEADLK:
00317               prError = PR_DEADLOCK_ERROR;
00318               break;
00319 #ifdef EDIRCORRUPTED
00320        case EDIRCORRUPTED:
00321               prError = PR_DIRECTORY_CORRUPTED_ERROR;
00322               break;
00323 #endif
00324 #ifdef EDQUOT
00325        case EDQUOT:
00326               prError = PR_NO_DEVICE_SPACE_ERROR;
00327               break;
00328 #endif
00329        case EEXIST:
00330               prError = PR_FILE_EXISTS_ERROR;
00331               break;
00332        case EFAULT:
00333               prError = PR_ACCESS_FAULT_ERROR;
00334               break;
00335        case EFBIG:
00336               prError = PR_FILE_TOO_BIG_ERROR;
00337               break;
00338        case EHOSTUNREACH:
00339               prError = PR_HOST_UNREACHABLE_ERROR;
00340               break;
00341        case EINPROGRESS:
00342               prError = PR_IN_PROGRESS_ERROR;
00343               break;
00344        case EINTR:
00345               prError = PR_PENDING_INTERRUPT_ERROR;
00346               break;
00347        case EINVAL:
00348               prError = PR_INVALID_ARGUMENT_ERROR;
00349               break;
00350        case EIO:
00351               prError = PR_IO_ERROR;
00352               break;
00353        case EISCONN:
00354               prError = PR_IS_CONNECTED_ERROR;
00355               break;
00356        case EISDIR:
00357               prError = PR_IS_DIRECTORY_ERROR;
00358               break;
00359        case ELOOP:
00360               prError = PR_LOOP_ERROR;
00361               break;
00362        case EMFILE:
00363               prError = PR_PROC_DESC_TABLE_FULL_ERROR;
00364               break;
00365        case EMLINK:
00366               prError = PR_MAX_DIRECTORY_ENTRIES_ERROR;
00367               break;
00368        case EMSGSIZE:
00369               prError = PR_INVALID_ARGUMENT_ERROR;
00370               break;
00371 #ifdef EMULTIHOP
00372        case EMULTIHOP:
00373               prError = PR_REMOTE_FILE_ERROR;
00374               break;
00375 #endif
00376        case ENAMETOOLONG:
00377               prError = PR_NAME_TOO_LONG_ERROR;
00378               break;
00379        case ENETUNREACH:
00380               prError = PR_NETWORK_UNREACHABLE_ERROR;
00381               break;
00382        case ENFILE:
00383               prError = PR_SYS_DESC_TABLE_FULL_ERROR;
00384               break;
00385        /*
00386         * On SCO OpenServer 5, ENOBUFS is defined as ENOSR.
00387         */
00388 #if defined(ENOBUFS) && (ENOBUFS != ENOSR)
00389        case ENOBUFS:
00390               prError = PR_INSUFFICIENT_RESOURCES_ERROR;
00391               break;
00392 #endif
00393        case ENODEV:
00394               prError = PR_FILE_NOT_FOUND_ERROR;
00395               break;
00396        case ENOENT:
00397               prError = PR_FILE_NOT_FOUND_ERROR;
00398               break;
00399        case ENOLCK:
00400               prError = PR_FILE_IS_LOCKED_ERROR;
00401               break;
00402 #ifdef ENOLINK 
00403        case ENOLINK:
00404               prError = PR_REMOTE_FILE_ERROR;
00405               break;
00406 #endif
00407        case ENOMEM:
00408               prError = PR_OUT_OF_MEMORY_ERROR;
00409               break;
00410        case ENOPROTOOPT:
00411               prError = PR_INVALID_ARGUMENT_ERROR;
00412               break;
00413        case ENOSPC:
00414               prError = PR_NO_DEVICE_SPACE_ERROR;
00415               break;
00416 #ifdef ENOSR
00417        case ENOSR:
00418               prError = PR_INSUFFICIENT_RESOURCES_ERROR;
00419               break;
00420 #endif
00421        case ENOTCONN:
00422               prError = PR_NOT_CONNECTED_ERROR;
00423               break;
00424        case ENOTDIR:
00425               prError = PR_NOT_DIRECTORY_ERROR;
00426               break;
00427        case ENOTSOCK:
00428               prError = PR_NOT_SOCKET_ERROR;
00429               break;
00430        case ENXIO:
00431               prError = PR_FILE_NOT_FOUND_ERROR;
00432               break;
00433        case EOPNOTSUPP:
00434               prError = PR_NOT_TCP_SOCKET_ERROR;
00435               break;
00436 #ifdef EOVERFLOW
00437        case EOVERFLOW:
00438               prError = PR_BUFFER_OVERFLOW_ERROR;
00439               break;
00440 #endif
00441        case EPERM:
00442               prError = PR_NO_ACCESS_RIGHTS_ERROR;
00443               break;
00444        case EPIPE:
00445               prError = PR_CONNECT_RESET_ERROR;
00446               break;
00447 #ifdef EPROTO
00448        case EPROTO:
00449               prError = PR_IO_ERROR;
00450               break;
00451 #endif
00452        case EPROTONOSUPPORT:
00453               prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR;
00454               break;
00455        case EPROTOTYPE:
00456               prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
00457               break;
00458        case ERANGE:
00459               prError = PR_INVALID_METHOD_ERROR;
00460               break;
00461        case EROFS:
00462               prError = PR_READ_ONLY_FILESYSTEM_ERROR;
00463               break;
00464        case ESPIPE:
00465               prError = PR_INVALID_METHOD_ERROR;
00466               break;
00467        case ETIMEDOUT:
00468               prError = PR_IO_TIMEOUT_ERROR;
00469               break;
00470 #if EWOULDBLOCK != EAGAIN
00471        case EWOULDBLOCK:
00472               prError = PR_WOULD_BLOCK_ERROR;
00473               break;
00474 #endif
00475        case EXDEV:
00476               prError = PR_NOT_SAME_DEVICE_ERROR;
00477               break;
00478        default:
00479               prError = PR_UNKNOWN_ERROR;
00480               break;
00481        }
00482        PR_SetError( prError, err );
00483 }
00484 
00485 /*
00486  * cipher_list is an integer array with the following values:
00487  *   -1: never enable this cipher
00488  *    0: cipher disabled
00489  *    1: cipher enabled
00490  */
00491 static int
00492 nss_parse_ciphers(const char *cipherstr, int cipher_list[ciphernum])
00493 {
00494        int i;
00495        char *cipher;
00496        char *ciphers;
00497        char *ciphertip;
00498        int action;
00499        int rv;
00500 
00501        /* All disabled to start */
00502        for (i=0; i<ciphernum; i++)
00503               cipher_list[i] = 0;
00504 
00505        ciphertip = strdup(cipherstr);
00506        cipher = ciphers = ciphertip;
00507 
00508        while (ciphers && (strlen(ciphers))) {
00509               while ((*cipher) && (isspace(*cipher)))
00510                      ++cipher;
00511 
00512               action = 1;
00513               switch(*cipher) {
00514               case '+': /* Add something */
00515                      action = 1;
00516                      cipher++;
00517                      break;
00518               case '-': /* Subtract something */
00519                      action = 0;
00520                      cipher++;
00521                      break;
00522               case '!':  /* Disable something */
00523                      action = -1;
00524                      cipher++;
00525                      break;
00526               default:
00527                      /* do nothing */
00528                      break;
00529               }
00530 
00531               if ((ciphers = strchr(cipher, ':'))) {
00532                      *ciphers++ = '\0';
00533               }
00534 
00535               /* Do the easy one first */
00536               if (!strcmp(cipher, "ALL")) {
00537                      for (i=0; i<ciphernum; i++) {
00538                             if (!(ciphers_def[i].attr & SSL_eNULL))
00539                                    cipher_list[i] = action;
00540                      }
00541               } else if (!strcmp(cipher, "COMPLEMENTOFALL")) {
00542                      for (i=0; i<ciphernum; i++) {
00543                             if ((ciphers_def[i].attr & SSL_eNULL))
00544                                    cipher_list[i] = action;
00545                      }
00546               } else if (!strcmp(cipher, "DEFAULT")) {
00547                      for (i=0; i<ciphernum; i++) {
00548                             cipher_list[i] = ciphers_def[i].enabled == SSL_ALLOWED ? 1 : 0;
00549                      }
00550               } else {
00551                      int mask = 0;
00552                      int strength = 0;
00553                      int protocol = 0;
00554                      char *c;
00555 
00556                      c = cipher;
00557                      while (c && (strlen(c))) {
00558 
00559                             if ((c = strchr(cipher, '+'))) {
00560                                    *c++ = '\0';
00561                             }
00562 
00563                             if (!strcmp(cipher, "RSA")) {
00564                                    mask |= SSL_RSA;
00565                             } else if ((!strcmp(cipher, "NULL")) || (!strcmp(cipher, "eNULL"))) {
00566                                    mask |= SSL_eNULL;
00567                             } else if (!strcmp(cipher, "AES")) {
00568                                    mask |= SSL_AES;
00569                             } else if (!strcmp(cipher, "3DES")) {
00570                                    mask |= SSL_3DES;
00571                             } else if (!strcmp(cipher, "DES")) {
00572                                    mask |= SSL_DES;
00573                             } else if (!strcmp(cipher, "RC4")) {
00574                                    mask |= SSL_RC4;
00575                             } else if (!strcmp(cipher, "RC2")) {
00576                                    mask |= SSL_RC2;
00577                             } else if (!strcmp(cipher, "MD5")) {
00578                                    mask |= SSL_MD5;
00579                             } else if ((!strcmp(cipher, "SHA")) || (!strcmp(cipher, "SHA1"))) {
00580                                    mask |= SSL_SHA1;
00581                             } else if (!strcmp(cipher, "SSLv2")) {
00582                                    protocol |= SSL2;
00583                             } else if (!strcmp(cipher, "SSLv3")) {
00584                                    protocol |= SSL3;
00585                             } else if (!strcmp(cipher, "TLSv1")) {
00586                                    protocol |= TLS1;
00587                             } else if (!strcmp(cipher, "HIGH")) {
00588                                    strength |= SSL_HIGH;
00589                             } else if (!strcmp(cipher, "MEDIUM")) {
00590                                    strength |= SSL_MEDIUM;
00591                             } else if (!strcmp(cipher, "LOW")) {
00592                                    strength |= SSL_LOW;
00593                             } else if ((!strcmp(cipher, "EXPORT")) || (!strcmp(cipher, "EXP"))) {
00594                                    strength |= SSL_EXPORT40|SSL_EXPORT56;
00595                             } else if (!strcmp(cipher, "EXPORT40")) {
00596                                    strength |= SSL_EXPORT40;
00597                             } else if (!strcmp(cipher, "EXPORT56")) {
00598                                    strength |= SSL_EXPORT56;
00599                             }
00600 
00601                             if (c)
00602                                    cipher = c;
00603 
00604                      } /* while */
00605 
00606                      /* If we have a mask, apply it. If not then perhaps they provided
00607                       * a specific cipher to enable.
00608                       */
00609                      if (mask || strength || protocol) {
00610                             for (i=0; i<ciphernum; i++) {
00611                                    if (((ciphers_def[i].attr & mask) ||
00612                                            (ciphers_def[i].strength & strength) ||
00613                                            (ciphers_def[i].version & protocol)) &&
00614                                           (cipher_list[i] != -1)) {
00615                                           /* Enable the NULL ciphers only if explicity
00616                                            * requested */
00617                                           if (ciphers_def[i].attr & SSL_eNULL) {
00618                                                  if (mask & SSL_eNULL)
00619                                                         cipher_list[i] = action;
00620                                           } else
00621                                                  cipher_list[i] = action;
00622                                    }
00623                             }
00624                      } else {
00625                             for (i=0; i<ciphernum; i++) {
00626                                    if (!strcmp(ciphers_def[i].ossl_name, cipher) &&
00627                                           cipher_list[1] != -1)
00628                                           cipher_list[i] = action;
00629                             }
00630                      }
00631               }
00632 
00633               if (ciphers)
00634                      cipher = ciphers;
00635        }
00636 
00637        /* See if any ciphers were enabled */
00638        rv = 0;
00639        for (i=0; i<ciphernum; i++) {
00640               if (cipher_list[i] == 1)
00641                      rv = 1;
00642        }
00643 
00644        free(ciphertip);
00645 
00646        return rv;
00647 }
00648 
00649 static int
00650 tlsm_parse_ciphers(tlsm_ctx *ctx, const char *str)
00651 {
00652        int cipher_state[ciphernum];
00653        int rv, i;
00654 
00655        if (!ctx)
00656               return 0;
00657 
00658        rv = nss_parse_ciphers(str, cipher_state);
00659 
00660        if (rv) {
00661               /* First disable everything */
00662               for (i = 0; i < SSL_NumImplementedCiphers; i++)
00663                      SSL_CipherPrefSet(ctx->tc_model, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED);
00664 
00665               /* Now enable what was requested */
00666               for (i=0; i<ciphernum; i++) {
00667                      SSLCipherSuiteInfo suite;
00668                      PRBool enabled;
00669 
00670                      if (SSL_GetCipherSuiteInfo(ciphers_def[i].num, &suite, sizeof suite)
00671                             == SECSuccess) {
00672                             enabled = cipher_state[i] < 0 ? 0 : cipher_state[i];
00673                             if (enabled == SSL_ALLOWED) {
00674                                    if (PK11_IsFIPS() && !suite.isFIPS)    
00675                                           enabled = SSL_NOT_ALLOWED;
00676                             }
00677                             SSL_CipherPrefSet(ctx->tc_model, ciphers_def[i].num, enabled);
00678                      }
00679               }
00680        }
00681 
00682        return rv == 1 ? 0 : -1;
00683 }
00684 
00685 static SECStatus
00686 tlsm_bad_cert_handler(void *arg, PRFileDesc *ssl)
00687 {
00688        SECStatus success = SECSuccess;
00689        PRErrorCode err;
00690        tlsm_ctx *ctx = (tlsm_ctx *)arg;
00691 
00692        if (!ssl || !ctx) {
00693               return SECFailure;
00694        }
00695 
00696        err = PORT_GetError();
00697 
00698        switch (err) {
00699        case SEC_ERROR_UNTRUSTED_ISSUER:
00700        case SEC_ERROR_UNKNOWN_ISSUER:
00701        case SEC_ERROR_EXPIRED_CERTIFICATE:
00702        case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
00703               if (ctx->tc_verify_cert) {
00704                      success = SECFailure;
00705               }
00706               break;
00707        /* we bypass NSS's hostname checks and do our own */
00708        case SSL_ERROR_BAD_CERT_DOMAIN:
00709               break;
00710        default:
00711               success = SECFailure;
00712               break;
00713        }
00714 
00715        return success;
00716 }
00717 
00718 static const char *
00719 tlsm_dump_security_status(PRFileDesc *fd)
00720 {
00721        char * cp;    /* bulk cipher name */
00722        char * ip;    /* cert issuer DN */
00723        char * sp;    /* cert subject DN */
00724        int    op;    /* High, Low, Off */
00725        int    kp0;   /* total key bits */
00726        int    kp1;   /* secret key bits */
00727        SSL3Statistics * ssl3stats = SSL_GetStatistics();
00728 
00729        SSL_SecurityStatus( fd, &op, &cp, &kp0, &kp1, &ip, &sp );
00730        Debug( LDAP_DEBUG_TRACE,
00731                  "TLS certificate verification: subject: %s, issuer: %s, cipher: %s, ",
00732                  sp ? sp : "-unknown-", ip ? ip : "-unknown-", cp ? cp : "-unknown-" );
00733        PR_Free(cp);
00734        PR_Free(ip);
00735        PR_Free(sp);
00736        Debug( LDAP_DEBUG_TRACE,
00737                  "security level: %s, secret key bits: %d, total key bits: %d, ",
00738                  ((op == SSL_SECURITY_STATUS_ON_HIGH) ? "high" :
00739                      ((op == SSL_SECURITY_STATUS_ON_LOW) ? "low" : "off")),
00740                  kp1, kp0 );
00741 
00742        Debug( LDAP_DEBUG_TRACE,
00743                  "cache hits: %ld, cache misses: %ld, cache not reusable: %ld\n",
00744                  ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
00745                  ssl3stats->hch_sid_cache_not_ok );
00746 
00747        return "";
00748 }
00749 
00750 static void
00751 tlsm_handshake_complete_cb( PRFileDesc *fd, void *client_data )
00752 {
00753        tlsm_dump_security_status( fd );
00754 }
00755 
00756 #ifdef READ_PASSWORD_FROM_FILE
00757 static char *
00758 tlsm_get_pin_from_file(const char *token_name, tlsm_ctx *ctx)
00759 {
00760        char *pwdstr = NULL;
00761        char *contents = NULL;
00762        char *lasts = NULL;
00763        char *line = NULL;
00764        char *candidate = NULL;
00765        PRFileInfo file_info;
00766        PRFileDesc *pwd_fileptr = PR_Open( ctx->tc_pin_file, PR_RDONLY, 00400 );
00767 
00768        /* open the password file */
00769        if ( !pwd_fileptr ) {
00770               PRErrorCode errcode = PR_GetError();
00771               Debug( LDAP_DEBUG_ANY,
00772                      "TLS: could not open security pin file %s - error %d:%s.\n",
00773                      ctx->tc_pin_file, errcode,
00774                      PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
00775               goto done;
00776        }
00777 
00778        /* get the file size */
00779        if ( PR_SUCCESS != PR_GetFileInfo( ctx->tc_pin_file, &file_info ) ) {
00780               PRErrorCode errcode = PR_GetError();
00781               Debug( LDAP_DEBUG_ANY,
00782                      "TLS: could not get file info from pin file %s - error %d:%s.\n",
00783                      ctx->tc_pin_file, errcode,
00784                      PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
00785               goto done;
00786        }
00787 
00788        /* create a buffer to hold the file contents */
00789        if ( !( contents = PR_MALLOC( file_info.size + 1 ) ) ) {
00790               PRErrorCode errcode = PR_GetError();
00791               Debug( LDAP_DEBUG_ANY,
00792                      "TLS: could not alloc a buffer for contents of pin file %s - error %d:%s.\n",
00793                      ctx->tc_pin_file, errcode,
00794                      PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
00795               goto done;
00796        }
00797 
00798        /* read file into the buffer */
00799        if( PR_Read( pwd_fileptr, contents, file_info.size ) <= 0 ) {
00800               PRErrorCode errcode = PR_GetError();
00801               Debug( LDAP_DEBUG_ANY,
00802                      "TLS: could not read the file contents from pin file %s - error %d:%s.\n",
00803                      ctx->tc_pin_file, errcode,
00804                      PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
00805               goto done;
00806        }
00807 
00808        /* format is [tokenname:]password EOL [tokenname:]password EOL ... */
00809        /* if you want to use a password containing a colon character, use
00810           the special tokenname "default" */
00811        for ( line = PL_strtok_r( contents, "\r\n", &lasts ); line;
00812              line = PL_strtok_r( NULL, "\r\n", &lasts ) ) {
00813               char *colon;
00814 
00815               if ( !*line ) {
00816                      continue; /* skip blank lines */
00817               }
00818               colon = PL_strchr( line, ':' );
00819               if ( colon ) {
00820                      if ( *(colon + 1) && token_name &&
00821                           !PL_strncmp( token_name, line, colon-line ) ) {
00822                             candidate = colon + 1; /* found a definite match */
00823                             break;
00824                      } else if ( !PL_strncmp( DEFAULT_TOKEN_NAME, line, colon-line ) ) {
00825                             candidate = colon + 1; /* found possible match */
00826                      }
00827               } else { /* no token name */
00828                      candidate = line;
00829               }
00830        }
00831 done:
00832        if ( pwd_fileptr ) {
00833               PR_Close( pwd_fileptr );
00834        }
00835        if ( candidate ) {
00836               pwdstr = PL_strdup( candidate );
00837        }
00838        PL_strfree( contents );
00839 
00840        return pwdstr;
00841 }
00842 #endif /* READ_PASSWORD_FROM_FILE */
00843 
00844 #ifdef READ_PASSWORD_FROM_STDIN
00845 /*
00846  * Turn the echoing off on a tty.
00847  */
00848 static void
00849 echoOff(int fd)
00850 {
00851        if ( isatty( fd ) ) {
00852               struct termios tio;
00853               tcgetattr( fd, &tio );
00854               tio.c_lflag &= ~ECHO;
00855               tcsetattr( fd, TCSAFLUSH, &tio );
00856        }
00857 }
00858 
00859 /*
00860  * Turn the echoing on on a tty.
00861  */
00862 static void
00863 echoOn(int fd)
00864 {
00865        if ( isatty( fd ) ) {
00866               struct termios tio;
00867               tcgetattr( fd, &tio );
00868               tio.c_lflag |= ECHO;
00869               tcsetattr( fd, TCSAFLUSH, &tio );
00870               tcsetattr( fd, TCSAFLUSH, &tio );
00871        }
00872 }
00873 #endif /* READ_PASSWORD_FROM_STDIN */
00874 
00875 /*
00876  * This does the actual work of reading the pin/password/pass phrase
00877  */
00878 static char *
00879 tlsm_get_pin(PK11SlotInfo *slot, PRBool retry, tlsm_ctx *ctx)
00880 {
00881        char *token_name = NULL;
00882        char *pwdstr = NULL;
00883 
00884        token_name = PK11_GetTokenName( slot );
00885 #ifdef READ_PASSWORD_FROM_FILE
00886        /* Try to get the passwords from the password file if it exists.
00887         * THIS IS UNSAFE and is provided for convenience only. Without this
00888         * capability the server would have to be started in foreground mode
00889         * if using an encrypted key.
00890         */
00891        if ( ctx->tc_pin_file ) {
00892               pwdstr = tlsm_get_pin_from_file( token_name, ctx );
00893        }
00894 #endif /* RETRIEVE_PASSWORD_FROM_FILE */
00895 #ifdef READ_PASSWORD_FROM_STDIN
00896        if ( !pwdstr ) {
00897               int infd = PR_FileDesc2NativeHandle( PR_STDIN );
00898               int isTTY = isatty( infd );
00899               unsigned char phrase[200];
00900               /* Prompt for password */
00901               if ( isTTY ) {
00902                      fprintf( stdout,
00903                              "Please enter pin, password, or pass phrase for security token '%s': ",
00904                              token_name ? token_name : DEFAULT_TOKEN_NAME );
00905                      echoOff( infd );
00906               }
00907               fgets( (char*)phrase, sizeof(phrase), stdin );
00908               if ( isTTY ) {
00909                      fprintf( stdout, "\n" );
00910                      echoOn( infd );
00911               }
00912               /* stomp on newline */
00913               phrase[strlen((char*)phrase)-1] = 0;
00914 
00915               pwdstr = PL_strdup( (char*)phrase );
00916        }
00917 
00918 #endif /* READ_PASSWORD_FROM_STDIN */
00919        return pwdstr;
00920 }
00921 
00922 /*
00923  * PKCS11 devices (including the internal softokn cert/key database)
00924  * may be protected by a pin or password or even pass phrase
00925  * MozNSS needs a way for the user to provide that
00926  */
00927 static char *
00928 tlsm_pin_prompt(PK11SlotInfo *slot, PRBool retry, void *arg)
00929 {
00930        tlsm_ctx *ctx = (tlsm_ctx *)arg;
00931 
00932        return tlsm_get_pin( slot, retry, ctx );
00933 }
00934 
00935 static SECStatus
00936 tlsm_get_basic_constraint_extension( CERTCertificate *cert,
00937                                                                 CERTBasicConstraints *cbcval )
00938 {
00939        SECItem encodedVal = { 0, NULL };
00940        SECStatus rc;
00941 
00942        rc = CERT_FindCertExtension( cert, SEC_OID_X509_BASIC_CONSTRAINTS,
00943                                                          &encodedVal);
00944        if ( rc != SECSuccess ) {
00945               return rc;
00946        }
00947 
00948        rc = CERT_DecodeBasicConstraintValue( cbcval, &encodedVal );
00949 
00950        /* free the raw extension data */
00951        PORT_Free( encodedVal.data );
00952 
00953        return rc;
00954 }
00955 
00956 static PRBool
00957 tlsm_cert_is_self_issued( CERTCertificate *cert )
00958 {
00959        /* A cert is self-issued if its subject and issuer are equal and
00960         * both are of non-zero length. 
00961         */
00962        PRBool is_self_issued = cert &&
00963               (PRBool)SECITEM_ItemsAreEqual( &cert->derIssuer, 
00964                                                                   &cert->derSubject ) &&
00965               cert->derSubject.len > 0;
00966        return is_self_issued;
00967 }
00968 
00969 static SECStatus
00970 tlsm_verify_cert(CERTCertDBHandle *handle, CERTCertificate *cert, void *pinarg,
00971                              PRBool checksig, SECCertificateUsage certUsage, int errorToIgnore )
00972 {
00973        CERTVerifyLog verifylog;
00974        SECStatus ret = SECSuccess;
00975        const char *name;
00976        int debug_level = LDAP_DEBUG_ANY;
00977 
00978        if ( errorToIgnore == -1 ) {
00979               debug_level = LDAP_DEBUG_TRACE;
00980        }
00981 
00982        /* the log captures information about every cert in the chain, so we can tell
00983           which cert caused the problem and what the problem was */
00984        memset( &verifylog, 0, sizeof( verifylog ) );
00985        verifylog.arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
00986        if ( verifylog.arena == NULL ) {
00987               Debug( LDAP_DEBUG_ANY,
00988                         "TLS certificate verification: Out of memory for certificate verification logger\n",
00989                         0, 0, 0 );
00990               return SECFailure;
00991        }
00992        ret = CERT_VerifyCertificate( handle, cert, checksig, certUsage, PR_Now(), pinarg, &verifylog,
00993                                                           NULL );
00994        if ( ( name = cert->subjectName ) == NULL ) {
00995               name = cert->nickname;
00996        }
00997        if ( verifylog.head == NULL ) {
00998               /* it is possible for CERT_VerifyCertificate return with an error with no logging */
00999               if ( ret != SECSuccess ) {
01000                      PRErrorCode errcode = PR_GetError();
01001                      Debug( debug_level,
01002                                "TLS: certificate [%s] is not valid - error %d:%s.\n",
01003                                name ? name : "(unknown)",
01004                                errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01005               }
01006        } else {
01007               const char *name;
01008               CERTVerifyLogNode *node;
01009 
01010               ret = SECSuccess; /* reset */
01011               node = verifylog.head;
01012               while ( node ) {
01013                      if ( ( name = node->cert->subjectName ) == NULL ) {
01014                             name = node->cert->nickname;
01015                      }
01016                      if ( node->error ) {
01017                             /* NSS does not like CA certs that have the basic constraints extension
01018                                with the CA flag set to FALSE - openssl doesn't check if the cert
01019                                is self issued */
01020                             if ( ( node->error == SEC_ERROR_CA_CERT_INVALID ) &&
01021                                     tlsm_cert_is_self_issued( node->cert ) ) {
01022                                    CERTBasicConstraints basicConstraint;
01023                                    SECStatus rv = tlsm_get_basic_constraint_extension( node->cert, &basicConstraint );
01024                                    if ( ( rv == SECSuccess ) && ( basicConstraint.isCA == PR_FALSE ) ) {
01025                                           Debug( LDAP_DEBUG_TRACE,
01026                                                     "TLS: certificate [%s] is not correct because it is a CA cert and the "
01027                                                     "BasicConstraint CA flag is set to FALSE - allowing for now, but "
01028                                                     "please fix your certs if possible\n", name, 0, 0 );
01029                                    } else { /* does not have basicconstraint, or some other error */
01030                                           ret = SECFailure;
01031                                           Debug( debug_level,
01032                                                     "TLS: certificate [%s] is not valid - CA cert is not valid\n",
01033                                                     name, 0, 0 );
01034                                    }
01035                             } else if ( errorToIgnore && ( node->error == errorToIgnore ) ) {
01036                                    Debug( debug_level,
01037                                              "TLS: Warning: ignoring error for certificate [%s] - error %ld:%s.\n",
01038                                              name, node->error, PR_ErrorToString( node->error, PR_LANGUAGE_I_DEFAULT ) );
01039                             } else {
01040                                    ret = SECFailure;
01041                                    Debug( debug_level,
01042                                              "TLS: certificate [%s] is not valid - error %ld:%s.\n",
01043                                              name, node->error, PR_ErrorToString( node->error, PR_LANGUAGE_I_DEFAULT ) );
01044                             }
01045                      }
01046                      CERT_DestroyCertificate( node->cert );
01047                      node = node->next;
01048               }
01049        }
01050 
01051        PORT_FreeArena( verifylog.arena, PR_FALSE );
01052 
01053        if ( ret == SECSuccess ) {
01054               Debug( LDAP_DEBUG_TRACE,
01055                         "TLS: certificate [%s] is valid\n", name, 0, 0 );
01056        } else if ( errorToIgnore == -1 ) {
01057               ret = SECSuccess;
01058        }
01059 
01060        return ret;
01061 }
01062 
01063 static SECStatus
01064 tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
01065                        PRBool checksig, PRBool isServer)
01066 {
01067        SECCertificateUsage certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer;
01068        SECStatus ret = SECSuccess;
01069        CERTCertificate *peercert = SSL_PeerCertificate( fd );
01070        int errorToIgnore = 0;
01071        tlsm_ctx *ctx = (tlsm_ctx *)arg;
01072 
01073        if (ctx && ctx->tc_warn_only )
01074               errorToIgnore = -1;
01075 
01076        ret = tlsm_verify_cert( ctx->tc_certdb, peercert,
01077                                                  SSL_RevealPinArg( fd ),
01078                                                  checksig, certUsage, errorToIgnore );
01079        CERT_DestroyCertificate( peercert );
01080 
01081        return ret;
01082 }
01083 
01084 static int
01085 tlsm_authenticate_to_slot( tlsm_ctx *ctx, PK11SlotInfo *slot )
01086 {
01087        int rc = -1;
01088 
01089        if ( SECSuccess != PK11_Authenticate( slot, PR_FALSE, ctx ) ) {
01090               char *token_name = PK11_GetTokenName( slot );
01091               PRErrorCode errcode = PR_GetError();
01092               Debug( LDAP_DEBUG_ANY,
01093                         "TLS: could not authenticate to the security token %s - error %d:%s.\n",
01094                         token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
01095                         PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01096        } else {
01097               rc = 0; /* success */
01098        }
01099 
01100        return rc;
01101 }
01102 
01103 static SECStatus
01104 tlsm_nss_shutdown_cb( void *appData, void *nssData )
01105 {
01106        SECStatus rc = SECSuccess;
01107 
01108        SSL_ShutdownServerSessionIDCache();
01109 
01110        if ( pem_module ) {
01111               SECMOD_UnloadUserModule( pem_module );
01112               SECMOD_DestroyModule( pem_module );
01113               pem_module = NULL;
01114        }
01115        return rc;
01116 }
01117 
01118 static PRCallOnceType tlsm_register_shutdown_callonce = {0,0};
01119 static PRStatus PR_CALLBACK
01120 tlsm_register_nss_shutdown_cb( void )
01121 {
01122        if ( SECSuccess == NSS_RegisterShutdown( tlsm_nss_shutdown_cb,
01123                                                                               NULL ) ) {
01124               return PR_SUCCESS;
01125        }
01126        return PR_FAILURE;
01127 }
01128 
01129 static PRStatus
01130 tlsm_register_nss_shutdown( void )
01131 {
01132        return PR_CallOnce( &tlsm_register_shutdown_callonce,
01133                                           tlsm_register_nss_shutdown_cb );
01134 }
01135 
01136 static int
01137 tlsm_init_pem_module( void )
01138 {
01139        int rc = 0;
01140        char *fullname = NULL;
01141        char *configstring = NULL;
01142 
01143        if ( pem_module ) {
01144               return rc;
01145        }
01146 
01147        /* not loaded - load it */
01148        /* get the system dependent library name */
01149        fullname = PR_GetLibraryName( NULL, PEM_LIBRARY );
01150        /* Load our PKCS#11 module */
01151        configstring = PR_smprintf( "library=%s name=" PEM_MODULE " parameters=\"\"", fullname );
01152        PL_strfree( fullname );
01153 
01154        pem_module = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE );
01155        PR_smprintf_free( configstring );
01156 
01157        if ( !pem_module || !pem_module->loaded ) {
01158               if ( pem_module ) {
01159                      SECMOD_DestroyModule( pem_module );
01160                      pem_module = NULL;
01161               }
01162               rc = -1;
01163        }
01164 
01165        return rc;
01166 }
01167 
01168 static void
01169 tlsm_add_pem_obj( tlsm_ctx *ctx, PK11GenericObject *obj )
01170 {
01171        int idx = ctx->tc_n_pem_objs;
01172        ctx->tc_n_pem_objs++;
01173        ctx->tc_pem_objs = (PK11GenericObject **)
01174               PORT_Realloc( ctx->tc_pem_objs, ctx->tc_n_pem_objs * sizeof( PK11GenericObject * ) );
01175        ctx->tc_pem_objs[idx] = obj;                                                                                                    
01176 }
01177 
01178 static void
01179 tlsm_free_pem_objs( tlsm_ctx *ctx )
01180 {
01181        /* free in reverse order of allocation */
01182        while ( ctx->tc_n_pem_objs-- ) {
01183               PK11_DestroyGenericObject( ctx->tc_pem_objs[ctx->tc_n_pem_objs] );
01184               ctx->tc_pem_objs[ctx->tc_n_pem_objs] = NULL;
01185        }
01186        PORT_Free(ctx->tc_pem_objs);
01187        ctx->tc_pem_objs = NULL;
01188        ctx->tc_n_pem_objs = 0;
01189 }
01190 
01191 static int
01192 tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca, PRBool istrusted )
01193 {
01194        CK_SLOT_ID slotID;
01195        PK11SlotInfo *slot = NULL;
01196        PK11GenericObject *rv;
01197        CK_ATTRIBUTE *attrs;
01198        CK_ATTRIBUTE theTemplate[20];
01199        CK_BBOOL cktrue = CK_TRUE;
01200        CK_BBOOL ckfalse = CK_FALSE;
01201        CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
01202        char tmpslotname[64];
01203        char *slotname = NULL;
01204        const char *ptr = NULL;
01205        char sep = PR_GetDirectorySeparator();
01206        PRFileInfo fi;
01207        PRStatus status;
01208 
01209        memset( &fi, 0, sizeof(fi) );
01210        status = PR_GetFileInfo( filename, &fi );
01211        if ( PR_SUCCESS != status) {
01212               PRErrorCode errcode = PR_GetError();
01213               Debug( LDAP_DEBUG_ANY,
01214                         "TLS: could not read certificate file %s - error %d:%s.\n",
01215                         filename, errcode,
01216                         PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01217               return -1;
01218        }
01219 
01220        if ( fi.type != PR_FILE_FILE ) {
01221               PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
01222               Debug( LDAP_DEBUG_ANY,
01223                         "TLS: error: the certificate file %s is not a file.\n",
01224                         filename, 0 ,0 );
01225               return -1;
01226        }
01227 
01228        attrs = theTemplate;
01229 
01230        if ( isca ) {
01231               slotID = 0; /* CA and trust objects use slot 0 */
01232               PR_snprintf( tmpslotname, sizeof(tmpslotname), TLSM_PEM_TOKEN_FMT, slotID );
01233               slotname = tmpslotname;
01234               istrusted = PR_TRUE;
01235        } else {
01236               if ( ctx->tc_slotname == NULL ) { /* need new slot */
01237                      if ( istrusted ) {
01238                             slotID = 0;
01239                      } else {
01240                             slotID = ++tlsm_slot_count;
01241                      }
01242                      ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
01243               }
01244               slotname = ctx->tc_slotname;
01245 
01246               if ( ( ptr = PL_strrchr( filename, sep ) ) ) {
01247                      PL_strfree( ctx->tc_certname );
01248                      ++ptr;
01249                      if ( istrusted ) {
01250                             /* pemnss conflates trusted certs with CA certs - since there can
01251                                be more than one CA cert in a file (e.g. ca-bundle.crt) pemnss
01252                                numbers each trusted cert - in the case of a server cert, there will be
01253                                only one, so it will be number 0 */
01254                             ctx->tc_certname = PR_smprintf( "%s:%s - 0", slotname, ptr );
01255                      } else {
01256                             ctx->tc_certname = PR_smprintf( "%s:%s", slotname, ptr );
01257                      }
01258               }
01259        }
01260 
01261        slot = PK11_FindSlotByName( slotname );
01262 
01263        if ( !slot ) {
01264               PRErrorCode errcode = PR_GetError();
01265               Debug( LDAP_DEBUG_ANY,
01266                         "TLS: could not find the slot for certificate %s - error %d:%s.\n",
01267                         ctx->tc_certname, errcode,
01268                         PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01269               return -1;
01270        }
01271 
01272        PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
01273        PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
01274        PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
01275        if ( istrusted ) {
01276               PK11_SETATTRS( attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
01277        } else {
01278               PK11_SETATTRS( attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
01279        }
01280        /* This loads the certificate in our PEM module into the appropriate
01281         * slot.
01282         */
01283        rv = PK11_CreateGenericObject( slot, theTemplate, 4, PR_FALSE /* isPerm */ );
01284 
01285        PK11_FreeSlot( slot );
01286 
01287        if ( !rv ) {
01288               PRErrorCode errcode = PR_GetError();
01289               Debug( LDAP_DEBUG_ANY,
01290                         "TLS: could not add the certificate %s - error %d:%s.\n",
01291                         ctx->tc_certname, errcode,
01292                         PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01293               return -1;
01294        }
01295 
01296        tlsm_add_pem_obj( ctx, rv );
01297 
01298        return 0;
01299 }
01300 
01301 static int
01302 tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
01303 {
01304        CK_SLOT_ID slotID;
01305        PK11SlotInfo * slot = NULL;
01306        PK11GenericObject *rv;
01307        CK_ATTRIBUTE *attrs;
01308        CK_ATTRIBUTE theTemplate[20];
01309        CK_BBOOL cktrue = CK_TRUE;
01310        CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
01311        int retcode = 0;
01312        PRFileInfo fi;
01313        PRStatus status;
01314 
01315        memset( &fi, 0, sizeof(fi) );
01316        status = PR_GetFileInfo( filename, &fi );
01317        if ( PR_SUCCESS != status) {
01318               PRErrorCode errcode = PR_GetError();
01319               Debug( LDAP_DEBUG_ANY,
01320                         "TLS: could not read key file %s - error %d:%s.\n",
01321                         filename, errcode,
01322                         PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01323               return -1;
01324        }
01325 
01326        if ( fi.type != PR_FILE_FILE ) {
01327               PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
01328               Debug( LDAP_DEBUG_ANY,
01329                         "TLS: error: the key file %s is not a file.\n",
01330                         filename, 0 ,0 );
01331               return -1;
01332        }
01333 
01334        attrs = theTemplate;
01335 
01336        if ( ctx->tc_slotname == NULL ) { /* need new slot */
01337               slotID = ++tlsm_slot_count;
01338               ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
01339        }
01340        slot = PK11_FindSlotByName( ctx->tc_slotname );
01341 
01342        if ( !slot ) {
01343               PRErrorCode errcode = PR_GetError();
01344               Debug( LDAP_DEBUG_ANY,
01345                         "TLS: could not find the slot %s for the private key - error %d:%s.\n",
01346                         ctx->tc_slotname, errcode,
01347                         PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01348               return -1;
01349        }
01350 
01351        PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
01352        PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
01353        PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
01354        rv = PK11_CreateGenericObject( slot, theTemplate, 3, PR_FALSE /* isPerm */ );
01355 
01356        if ( !rv ) {
01357               PRErrorCode errcode = PR_GetError();
01358               Debug( LDAP_DEBUG_ANY,
01359                         "TLS: could not add the certificate %s - error %d:%s.\n",
01360                         ctx->tc_certname, errcode,
01361                         PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01362               retcode = -1;
01363        } else {
01364               /* When adding an encrypted key the PKCS#11 will be set as removed */
01365               /* This will force the token to be seen as re-inserted */
01366               SECMOD_WaitForAnyTokenEvent( pem_module, 0, 0 );
01367               PK11_IsPresent( slot );
01368               retcode = 0;
01369        }
01370 
01371        PK11_FreeSlot( slot );
01372 
01373        if ( !retcode ) {
01374               tlsm_add_pem_obj( ctx, rv );
01375        }
01376        return retcode;
01377 }
01378 
01379 static int
01380 tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir )
01381 {
01382        PRBool isca = PR_TRUE;
01383        PRStatus status = PR_SUCCESS;
01384        PRErrorCode errcode = PR_SUCCESS;
01385 
01386        if ( !cacertfile && !cacertdir ) {
01387               /* no checking - not good, but allowed */
01388               return 0;
01389        }
01390 
01391        if ( cacertfile ) {
01392               int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca, PR_TRUE );
01393               if ( rc ) {
01394                      errcode = PR_GetError();
01395                      Debug( LDAP_DEBUG_ANY,
01396                                "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
01397                                cacertfile, errcode,
01398                                PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01399                      /* failure with cacertfile is a hard failure even if cacertdir is
01400                         also specified and contains valid CA cert files */
01401                      status = PR_FAILURE;
01402               } else {
01403                      Debug( LDAP_DEBUG_TRACE,
01404                                "TLS: loaded CA certificate file %s.\n",
01405                                cacertfile, 0, 0 );
01406               }
01407        }
01408 
01409        /* if cacertfile above failed, we will return failure, even
01410           if there is a valid CA cert in cacertdir - but we still
01411           process cacertdir in case the user has enabled trace level
01412           debugging so they can see the processing for cacertdir too */
01413        /* any cacertdir failures are "soft" failures - if the user specifies
01414           no cert checking, then we allow the tls/ssl to continue, no matter
01415           what was specified for cacertdir, or the contents of the directory
01416           - this is different behavior than that of cacertfile */
01417        if ( cacertdir ) {
01418               PRFileInfo fi;
01419               PRDir *dir;
01420               PRDirEntry *entry;
01421               PRStatus fistatus = PR_FAILURE;
01422 
01423               memset( &fi, 0, sizeof(fi) );
01424               fistatus = PR_GetFileInfo( cacertdir, &fi );
01425               if ( PR_SUCCESS != fistatus) {
01426                      errcode = PR_GetError();
01427                      Debug( LDAP_DEBUG_ANY,
01428                                "TLS: could not get info about the CA certificate directory %s - error %d:%s.\n",
01429                                cacertdir, errcode,
01430                                PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01431                      goto done;
01432               }
01433 
01434               if ( fi.type != PR_FILE_DIRECTORY ) {
01435                      Debug( LDAP_DEBUG_ANY,
01436                                "TLS: error: the CA certificate directory %s is not a directory.\n",
01437                                cacertdir, 0 ,0 );
01438                      goto done;
01439               }
01440 
01441               dir = PR_OpenDir( cacertdir );
01442               if ( NULL == dir ) {
01443                      errcode = PR_GetError();
01444                      Debug( LDAP_DEBUG_ANY,
01445                                "TLS: could not open the CA certificate directory %s - error %d:%s.\n",
01446                                cacertdir, errcode,
01447                                PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01448                      goto done;
01449               }
01450 
01451               do {
01452                      entry = PR_ReadDir( dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN );
01453                      if ( ( NULL != entry ) && ( NULL != entry->name ) ) {
01454                             char *fullpath = NULL;
01455                             char *ptr;
01456 
01457                             ptr = PL_strrstr( entry->name, PEM_CA_HASH_FILE_SUFFIX );
01458                             if ( ( ptr == NULL ) || ( *(ptr + PEM_CA_HASH_FILE_SUFFIX_LEN) != '\0' ) ) {
01459                                    Debug( LDAP_DEBUG_TRACE,
01460                                              "TLS: file %s does not end in [%s] - does not appear to be a CA certificate "
01461                                              "directory file with a properly hashed file name - skipping.\n",
01462                                              entry->name, PEM_CA_HASH_FILE_SUFFIX, 0 );
01463                                    continue;
01464                             }
01465                             fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
01466                             if ( !tlsm_add_cert_from_file( ctx, fullpath, isca, PR_TRUE ) ) {
01467                                    Debug( LDAP_DEBUG_TRACE,
01468                                              "TLS: loaded CA certificate file %s from CA certificate directory %s.\n",
01469                                              fullpath, cacertdir, 0 );
01470                             } else {
01471                                    errcode = PR_GetError();
01472                                    Debug( LDAP_DEBUG_TRACE,
01473                                              "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
01474                                              fullpath, errcode,
01475                                              PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01476                             }
01477                             PR_smprintf_free( fullpath );
01478                      }
01479               } while ( NULL != entry );
01480               PR_CloseDir( dir );
01481        }
01482 done:
01483        if ( status != PR_SUCCESS ) {
01484               return -1;
01485        }
01486 
01487        return 0;
01488 }
01489 
01490 /*
01491  * NSS supports having multiple cert/key databases in the same
01492  * directory, each one having a unique string prefix e.g.
01493  * slapd-01-cert8.db - the prefix here is "slapd-01-"
01494  * this function examines the given certdir - if it looks like
01495  * /path/to/directory/prefix it will return the
01496  * /path/to/directory part in realcertdir, and the prefix in prefix
01497  */
01498 static void
01499 tlsm_get_certdb_prefix( const char *certdir, char **realcertdir, char **prefix )
01500 {
01501        char sep = PR_GetDirectorySeparator();
01502        char *ptr = NULL;
01503        struct PRFileInfo prfi;
01504        PRStatus prc;
01505 
01506        *realcertdir = (char *)certdir; /* default is the one passed in */
01507 
01508        /* if certdir is not given, just return */
01509        if ( !certdir ) {
01510               return;
01511        }
01512 
01513        prc = PR_GetFileInfo( certdir, &prfi );
01514        /* if certdir exists (file or directory) then it cannot specify a prefix */
01515        if ( prc == PR_SUCCESS ) {
01516               return;
01517        }
01518 
01519        /* if certdir was given, and there is a '/' in certdir, see if there
01520           is anything after the last '/' - if so, assume it is the prefix */
01521        if ( ( ( ptr = strrchr( certdir, sep ) ) ) && *(ptr+1) ) {
01522               *realcertdir = PL_strndup( certdir, ptr-certdir );
01523               *prefix = PL_strdup( ptr+1 );
01524        }
01525 
01526        return;
01527 }
01528 
01529 /*
01530  * This is the part of the init we defer until we get the
01531  * actual security configuration information.  This is
01532  * only called once, protected by a PRCallOnce
01533  * NOTE: This must be done before the first call to SSL_ImportFD,
01534  * especially the setting of the policy
01535  * NOTE: This must be called after fork()
01536  */
01537 static int
01538 tlsm_deferred_init( void *arg )
01539 {
01540        tlsm_ctx *ctx = (tlsm_ctx *)arg;
01541        struct ldaptls *lt = ctx->tc_config;
01542        const char *securitydirs[3];
01543        int ii;
01544        int nn;
01545        PRErrorCode errcode = 1;
01546 #ifdef HAVE_NSS_INITCONTEXT
01547        NSSInitParameters initParams;
01548        NSSInitContext *initctx = NULL;
01549 #endif
01550        SECStatus rc;
01551        int done = 0;
01552 
01553 #ifdef HAVE_SECMOD_RESTARTMODULES
01554        /* NSS enforces the pkcs11 requirement that modules should be unloaded after
01555           a fork() - since there is no portable way to determine if NSS has been
01556           already initialized in a parent process, we just call SECMOD_RestartModules
01557           with force == FALSE - if the module has been unloaded due to a fork, it will
01558           be reloaded, otherwise, it is a no-op */
01559        if ( SECFailure == ( rc = SECMOD_RestartModules(PR_FALSE /* do not force */) ) ) {
01560               errcode = PORT_GetError();
01561               if ( errcode != SEC_ERROR_NOT_INITIALIZED ) {
01562                      Debug( LDAP_DEBUG_TRACE,
01563                                "TLS: could not restart the security modules: %d:%s\n",
01564                                errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
01565               } else {
01566                      errcode = 1;
01567               }
01568        }
01569 #endif
01570 
01571 #ifdef HAVE_NSS_INITCONTEXT
01572        memset( &initParams, 0, sizeof( initParams ) );
01573        initParams.length = sizeof( initParams );
01574 #endif /* HAVE_NSS_INITCONTEXT */
01575 
01576 #ifdef LDAP_R_COMPILE
01577        if ( PR_CallOnce( &tlsm_init_mutex_callonce, tlsm_thr_init_callonce ) ) {
01578               return -1;
01579        }
01580 #endif /* LDAP_R_COMPILE */
01581 
01582 #ifndef HAVE_NSS_INITCONTEXT
01583        if ( !NSS_IsInitialized() ) {
01584 #endif /* HAVE_NSS_INITCONTEXT */
01585               /*
01586                 MOZNSS_DIR will override everything else - you can
01587                 always set MOZNSS_DIR to force the use of this
01588                 directory
01589                 If using MOZNSS, specify the location of the moznss db dir
01590                 in the cacertdir directive of the OpenLDAP configuration.
01591                 DEFAULT_MOZNSS_DIR will only be used if the code cannot
01592                 find a security dir to use based on the current
01593                 settings
01594               */
01595               nn = 0;
01596               securitydirs[nn++] = PR_GetEnv( "MOZNSS_DIR" );
01597               securitydirs[nn++] = lt->lt_cacertdir;
01598               securitydirs[nn++] = PR_GetEnv( "DEFAULT_MOZNSS_DIR" );
01599               for ( ii = 0; !done && ( ii < nn ); ++ii ) {
01600                      char *realcertdir = NULL;
01601                      const char *defprefix = "";
01602                      char *prefix = (char *)defprefix;
01603                      const char *securitydir = securitydirs[ii];
01604                      if ( NULL == securitydir ) {
01605                             continue;
01606                      }
01607 
01608                      tlsm_get_certdb_prefix( securitydir, &realcertdir, &prefix );
01609                      LDAP_MUTEX_LOCK( &tlsm_init_mutex );
01610 
01611 #ifdef HAVE_NSS_INITCONTEXT
01612 #ifdef INITCONTEXT_HACK
01613                      if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
01614                             rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
01615                      } else {
01616                             initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
01617                                                                          &initParams, NSS_INIT_READONLY );
01618                             rc = (initctx == NULL) ? SECFailure : SECSuccess;
01619                      }
01620 #else
01621                      initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
01622                                                                   &initParams, NSS_INIT_READONLY );
01623                      rc = (initctx == NULL) ? SECFailure : SECSuccess;
01624 #endif
01625 #else
01626                      rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
01627 #endif
01628 
01629                      LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
01630 
01631                      if ( rc != SECSuccess ) {
01632                             errcode = PORT_GetError();
01633                             if ( securitydirs[ii] != lt->lt_cacertdir) {
01634                                    Debug( LDAP_DEBUG_TRACE,
01635                                              "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
01636                                              realcertdir, prefix, errcode );
01637                             }
01638                      } else {
01639                             /* success */
01640                             Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s prefix %s.\n",
01641                                       realcertdir, prefix, 0 );
01642                             errcode = 0;
01643                             done = 1;
01644                      }
01645                      if ( realcertdir != securitydir ) {
01646                             PL_strfree( realcertdir );
01647                      }
01648                      if ( prefix != defprefix ) {
01649                             PL_strfree( prefix );
01650                      }
01651               }
01652 
01653               if ( errcode ) { /* no moznss db found, or not using moznss db */
01654                      LDAP_MUTEX_LOCK( &tlsm_init_mutex );
01655 #ifdef HAVE_NSS_INITCONTEXT
01656                      int flags = NSS_INIT_READONLY|NSS_INIT_NOCERTDB|NSS_INIT_NOMODDB;
01657 #ifdef INITCONTEXT_HACK
01658                      if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
01659                             rc = NSS_NoDB_Init( NULL );
01660                      } else {
01661                             initctx = NSS_InitContext( "", "", "", SECMOD_DB,
01662                                                                          &initParams, flags );
01663                             rc = (initctx == NULL) ? SECFailure : SECSuccess;
01664                      }
01665 #else
01666                      initctx = NSS_InitContext( "", "", "", SECMOD_DB,
01667                                                                   &initParams, flags );
01668                      rc = (initctx == NULL) ? SECFailure : SECSuccess;
01669 #endif
01670 #else
01671                      rc = NSS_NoDB_Init( NULL );
01672 #endif
01673                      LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
01674                      if ( rc != SECSuccess ) {
01675                             errcode = PORT_GetError();
01676                             Debug( LDAP_DEBUG_ANY,
01677                                       "TLS: could not initialize moznss - error %d:%s.\n",
01678                                       errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
01679                             return -1;
01680                      }
01681 
01682 #ifdef HAVE_NSS_INITCONTEXT
01683                      ctx->tc_initctx = initctx;
01684 #endif
01685 
01686                      /* initialize the PEM module */
01687                      LDAP_MUTEX_LOCK( &tlsm_init_mutex );
01688                      if ( tlsm_init_pem_module() ) {
01689                             LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
01690                             errcode = PORT_GetError();
01691                             Debug( LDAP_DEBUG_ANY,
01692                                       "TLS: could not initialize moznss PEM module - error %d:%s.\n",
01693                                       errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
01694                             return -1;
01695                      }
01696                      LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
01697 
01698                      if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) {
01699                             /* if we tried to use lt->lt_cacertdir as an NSS key/cert db, errcode 
01700                                will be a value other than 1 - print an error message so that the
01701                                user will know that failed too */
01702                             if ( ( errcode != 1 ) && ( lt->lt_cacertdir ) ) {
01703                                    char *realcertdir = NULL;
01704                                    char *prefix = NULL;
01705                                    tlsm_get_certdb_prefix( lt->lt_cacertdir, &realcertdir, &prefix );
01706                                    Debug( LDAP_DEBUG_TRACE,
01707                                              "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
01708                                              realcertdir, prefix ? prefix : "", errcode );
01709                                    if ( realcertdir != lt->lt_cacertdir ) {
01710                                           PL_strfree( realcertdir );
01711                                    }
01712                                    PL_strfree( prefix );
01713                             }
01714                             return -1;
01715                      }
01716 
01717                      ctx->tc_using_pem = PR_TRUE;
01718               }
01719 
01720 #ifdef HAVE_NSS_INITCONTEXT
01721               if ( !ctx->tc_initctx ) {
01722                      ctx->tc_initctx = initctx;
01723               }
01724 #endif
01725 
01726               NSS_SetDomesticPolicy();
01727 
01728               PK11_SetPasswordFunc( tlsm_pin_prompt );
01729 
01730               /* register cleanup function */
01731               if ( tlsm_register_nss_shutdown() ) {
01732                      errcode = PORT_GetError();
01733                      Debug( LDAP_DEBUG_ANY,
01734                                "TLS: could not register NSS shutdown function: %d:%s\n",
01735                                errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
01736                      return -1;
01737               }
01738 
01739               if  ( ctx->tc_is_server ) {
01740                      LDAP_MUTEX_LOCK( &tlsm_init_mutex );
01741                      /* 0 means use the defaults here */
01742                      SSL_ConfigServerSessionIDCache( 0, 0, 0, NULL );
01743                      LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
01744               }
01745 
01746 #ifndef HAVE_NSS_INITCONTEXT
01747        }
01748 #endif /* HAVE_NSS_INITCONTEXT */
01749 
01750        return 0;
01751 }
01752 
01753 static int
01754 tlsm_authenticate( tlsm_ctx *ctx, const char *certname, const char *pininfo )
01755 {
01756        const char *colon = NULL;
01757        char *token_name = NULL;
01758        PK11SlotInfo *slot = NULL;
01759        int rc = -1;
01760 
01761        if ( !certname || !*certname ) {
01762               return 0;
01763        }
01764 
01765        if ( ( colon = PL_strchr( certname, ':' ) ) ) {
01766               token_name = PL_strndup( certname, colon-certname );
01767        }
01768 
01769        if ( token_name ) {
01770               slot = PK11_FindSlotByName( token_name );
01771        } else {
01772               slot = PK11_GetInternalKeySlot();
01773        }
01774 
01775        if ( !slot ) {
01776               PRErrorCode errcode = PR_GetError();
01777               Debug( LDAP_DEBUG_ANY,
01778                         "TLS: could not find the slot for security token %s - error %d:%s.\n",
01779                         token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
01780                         PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01781               goto done;
01782        }
01783 
01784        rc = tlsm_authenticate_to_slot( ctx, slot );
01785 
01786 done:
01787        PL_strfree( token_name );
01788        if ( slot ) {
01789               PK11_FreeSlot( slot );
01790        }
01791 
01792        return rc;
01793 }
01794 
01795 /*
01796  * Find and verify the certificate.
01797  * Either fd is given, in which case the cert will be taken from it via SSL_PeerCertificate
01798  * or certname is given, and it will be searched for by name
01799  */
01800 static int
01801 tlsm_find_and_verify_cert_key(tlsm_ctx *ctx, PRFileDesc *fd, const char *certname, int isServer, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
01802 {
01803        CERTCertificate *cert = NULL;
01804        int rc = -1;
01805        void *pin_arg = NULL;
01806        SECKEYPrivateKey *key = NULL;
01807 
01808        pin_arg = SSL_RevealPinArg( fd );
01809        if ( certname ) {
01810               cert = PK11_FindCertFromNickname( certname, pin_arg );
01811               if ( !cert ) {
01812                      PRErrorCode errcode = PR_GetError();
01813                      Debug( LDAP_DEBUG_ANY,
01814                                "TLS: error: the certificate %s could not be found in the database - error %d:%s\n",
01815                                certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01816                      return -1;
01817               }
01818        } else {
01819               /* we are verifying the peer cert
01820                  we also need to swap the isServer meaning */
01821               cert = SSL_PeerCertificate( fd );
01822               if ( !cert ) {
01823                      PRErrorCode errcode = PR_GetError();
01824                      Debug( LDAP_DEBUG_ANY,
01825                                "TLS: error: could not get the certificate from the peer connection - error %d:%s\n",
01826                                errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), NULL );
01827                      return -1;
01828               }
01829               isServer = !isServer; /* verify the peer's cert instead */
01830        }
01831 
01832        if ( ctx->tc_slotname ) {
01833               PK11SlotInfo *slot = PK11_FindSlotByName( ctx->tc_slotname );
01834               key = PK11_FindPrivateKeyFromCert( slot, cert, NULL );
01835               PK11_FreeSlot( slot );
01836        } else {
01837               key = PK11_FindKeyByAnyCert( cert, pin_arg );
01838        }
01839 
01840        if (key) {
01841               SECCertificateUsage certUsage;
01842               PRBool checkSig = PR_TRUE;
01843               SECStatus status;
01844               /* may not have a CA cert - ok - ignore SEC_ERROR_UNKNOWN_ISSUER */
01845               int errorToIgnore = SEC_ERROR_UNKNOWN_ISSUER;
01846 
01847               if ( pRetKey ) {
01848                      *pRetKey = key; /* caller will deal with this */
01849               } else {
01850                      SECKEY_DestroyPrivateKey( key );
01851               }
01852               if ( isServer ) {
01853                      certUsage = certificateUsageSSLServer;
01854               } else {
01855                      certUsage = certificateUsageSSLClient;
01856               }
01857               if ( ctx->tc_verify_cert ) {
01858                      checkSig = PR_TRUE;
01859               } else {
01860                      checkSig = PR_FALSE;
01861               }
01862               if ( ctx->tc_warn_only ) {
01863                      errorToIgnore = -1;
01864               }
01865               status = tlsm_verify_cert( ctx->tc_certdb, cert, pin_arg,
01866                                                            checkSig, certUsage, errorToIgnore );
01867               if ( status == SECSuccess ) {
01868                      rc = 0;
01869               }
01870        } else {
01871               PRErrorCode errcode = PR_GetError();
01872               Debug( LDAP_DEBUG_ANY,
01873                         "TLS: error: could not find the private key for certificate %s - error %d:%s\n",
01874                         certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
01875        }
01876 
01877        if ( pRetCert ) {
01878               *pRetCert = cert; /* caller will deal with this */
01879        } else {
01880               CERT_DestroyCertificate( cert );
01881        }
01882 
01883     return rc;
01884 }
01885 
01886 static int
01887 tlsm_get_client_auth_data( void *arg, PRFileDesc *fd,
01888                                              CERTDistNames *caNames, CERTCertificate **pRetCert,
01889                                              SECKEYPrivateKey **pRetKey )
01890 {
01891        tlsm_ctx *ctx = (tlsm_ctx *)arg;
01892        int rc;
01893        PRBool saveval;
01894 
01895        /* don't need caNames - this function will call CERT_VerifyCertificateNow
01896           which will verify the cert against the known CAs */
01897        saveval = ctx->tc_warn_only;
01898        ctx->tc_warn_only = PR_TRUE;
01899        rc = tlsm_find_and_verify_cert_key( ctx, fd, ctx->tc_certname, 0, pRetCert, pRetKey );
01900        ctx->tc_warn_only = saveval;
01901        if ( rc ) {
01902               Debug( LDAP_DEBUG_ANY,
01903                         "TLS: error: unable to perform client certificate authentication for "
01904                         "certificate named %s\n", ctx->tc_certname, 0, 0 );
01905               if ( pRetKey && *pRetKey ) {
01906                      SECKEY_DestroyPrivateKey( *pRetKey );
01907                      *pRetKey = NULL;
01908               }
01909               if ( pRetCert && *pRetCert ) {
01910                      CERT_DestroyCertificate( *pRetCert );
01911                      *pRetCert = NULL;
01912               }
01913               return SECFailure;
01914        }
01915 
01916        return SECSuccess;
01917 }
01918 
01919 /*
01920  * ctx must have a tc_model that is valid
01921  * certname is in the form [<tokenname>:]<certnickname>
01922  * where <tokenname> is the name of the PKCS11 token
01923  * and <certnickname> is the nickname of the cert/key in
01924  * the database
01925 */
01926 static int
01927 tlsm_clientauth_init( tlsm_ctx *ctx )
01928 {
01929        SECStatus status = SECFailure;
01930        int rc;
01931        PRBool saveval;
01932 
01933        saveval = ctx->tc_warn_only;
01934        ctx->tc_warn_only = PR_TRUE;
01935        rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, 0, NULL, NULL );
01936        ctx->tc_warn_only = saveval;
01937        if ( rc ) {
01938               Debug( LDAP_DEBUG_ANY,
01939                         "TLS: error: unable to set up client certificate authentication for "
01940                         "certificate named %s\n", ctx->tc_certname, 0, 0 );
01941               return -1;
01942        }
01943 
01944        status = SSL_GetClientAuthDataHook( ctx->tc_model,
01945                                                                       tlsm_get_client_auth_data,
01946                                                                       (void *)ctx );
01947 
01948        return ( status == SECSuccess ? 0 : -1 );
01949 }
01950 
01951 /*
01952  * Tear down the TLS subsystem. Should only be called once.
01953  */
01954 static void
01955 tlsm_destroy( void )
01956 {
01957 #ifdef LDAP_R_COMPILE
01958        ldap_pvt_thread_mutex_destroy( &tlsm_init_mutex );
01959        ldap_pvt_thread_mutex_destroy( &tlsm_pem_mutex );
01960 #endif
01961 }
01962 
01963 static struct ldaptls *
01964 tlsm_copy_config ( const struct ldaptls *config )
01965 {
01966        struct ldaptls *copy;
01967 
01968        assert(config);
01969 
01970        copy = LDAP_MALLOC(sizeof(*copy));
01971        if (!copy)
01972               return NULL;
01973 
01974        memset(copy, 0, sizeof(*copy));
01975 
01976        if (config->lt_certfile)
01977               copy->lt_certfile = LDAP_STRDUP(config->lt_certfile);
01978        if (config->lt_keyfile)
01979               copy->lt_keyfile = LDAP_STRDUP(config->lt_keyfile);
01980        if (config->lt_dhfile)
01981               copy->lt_dhfile = LDAP_STRDUP(config->lt_dhfile);
01982        if (config->lt_cacertfile)
01983               copy->lt_cacertfile = LDAP_STRDUP(config->lt_cacertfile);
01984        if (config->lt_cacertdir)
01985               copy->lt_cacertdir = LDAP_STRDUP(config->lt_cacertdir);
01986        if (config->lt_ciphersuite)
01987               copy->lt_ciphersuite = LDAP_STRDUP(config->lt_ciphersuite);
01988        if (config->lt_crlfile)
01989               copy->lt_crlfile = LDAP_STRDUP(config->lt_crlfile);
01990        if (config->lt_randfile)
01991               copy->lt_randfile = LDAP_STRDUP(config->lt_randfile);
01992 
01993        copy->lt_protocol_min = config->lt_protocol_min;
01994 
01995        return copy;
01996 }
01997 
01998 static void
01999 tlsm_free_config ( struct ldaptls *config )
02000 {
02001        assert(config);
02002 
02003        if (config->lt_certfile)
02004               LDAP_FREE(config->lt_certfile);
02005        if (config->lt_keyfile)
02006               LDAP_FREE(config->lt_keyfile);
02007        if (config->lt_dhfile)
02008               LDAP_FREE(config->lt_dhfile);
02009        if (config->lt_cacertfile)
02010               LDAP_FREE(config->lt_cacertfile);
02011        if (config->lt_cacertdir)
02012               LDAP_FREE(config->lt_cacertdir);
02013        if (config->lt_ciphersuite)
02014               LDAP_FREE(config->lt_ciphersuite);
02015        if (config->lt_crlfile)
02016               LDAP_FREE(config->lt_crlfile);
02017        if (config->lt_randfile)
02018               LDAP_FREE(config->lt_randfile);
02019 
02020        LDAP_FREE(config);
02021 }
02022 
02023 static tls_ctx *
02024 tlsm_ctx_new ( struct ldapoptions *lo )
02025 {
02026        tlsm_ctx *ctx;
02027 
02028        ctx = LDAP_MALLOC( sizeof (*ctx) );
02029        if ( ctx ) {
02030               ctx->tc_refcnt = 1;
02031 #ifdef LDAP_R_COMPILE
02032               ldap_pvt_thread_mutex_init( &ctx->tc_refmutex );
02033 #endif
02034               ctx->tc_config = NULL; /* populated later by tlsm_ctx_init */
02035               ctx->tc_certdb = NULL;
02036               ctx->tc_certname = NULL;
02037               ctx->tc_pin_file = NULL;
02038               ctx->tc_model = NULL;
02039               memset(&ctx->tc_callonce, 0, sizeof(ctx->tc_callonce));
02040               ctx->tc_require_cert = lo->ldo_tls_require_cert;
02041               ctx->tc_verify_cert = PR_FALSE;
02042               ctx->tc_using_pem = PR_FALSE;
02043               ctx->tc_slotname = NULL;
02044 #ifdef HAVE_NSS_INITCONTEXT
02045               ctx->tc_initctx = NULL;
02046 #endif /* HAVE_NSS_INITCONTEXT */
02047               ctx->tc_pem_objs = NULL;
02048               ctx->tc_n_pem_objs = 0;
02049               ctx->tc_warn_only = PR_FALSE;
02050        }
02051        return (tls_ctx *)ctx;
02052 }
02053 
02054 static void
02055 tlsm_ctx_ref( tls_ctx *ctx )
02056 {
02057        tlsm_ctx *c = (tlsm_ctx *)ctx;
02058        LDAP_MUTEX_LOCK( &c->tc_refmutex );
02059        c->tc_refcnt++;
02060        LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
02061 }
02062 
02063 static void
02064 tlsm_ctx_free ( tls_ctx *ctx )
02065 {
02066        tlsm_ctx *c = (tlsm_ctx *)ctx;
02067        int refcount;
02068 
02069        if ( !c ) return;
02070 
02071        LDAP_MUTEX_LOCK( &c->tc_refmutex );
02072        refcount = --c->tc_refcnt;
02073        LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
02074        if ( refcount )
02075               return;
02076        if ( c->tc_model )
02077               PR_Close( c->tc_model );
02078        c->tc_certdb = NULL; /* if not the default, may have to clean up */
02079        PL_strfree( c->tc_certname );
02080        c->tc_certname = NULL;
02081        PL_strfree( c->tc_pin_file );
02082        c->tc_pin_file = NULL;
02083        PL_strfree( c->tc_slotname );             
02084        tlsm_free_pem_objs( c );
02085 #ifdef HAVE_NSS_INITCONTEXT
02086        if ( c->tc_initctx ) {
02087               LDAP_MUTEX_LOCK( &tlsm_init_mutex );
02088               if ( NSS_ShutdownContext( c->tc_initctx ) ) {
02089                      PRErrorCode errcode = PR_GetError();
02090                      Debug( LDAP_DEBUG_ANY,
02091                                "TLS: could not shutdown NSS - error %d:%s.\n",
02092                                errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
02093               }
02094               LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
02095        }
02096        c->tc_initctx = NULL;
02097 #endif /* HAVE_NSS_INITCONTEXT */
02098 #ifdef LDAP_R_COMPILE
02099        ldap_pvt_thread_mutex_destroy( &c->tc_refmutex );
02100 #endif
02101 
02102        if ( c->tc_config )
02103               tlsm_free_config( c->tc_config );
02104 
02105        LDAP_FREE( c );
02106 }
02107 
02108 /*
02109  * initialize a new TLS context
02110  */
02111 static int
02112 tlsm_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
02113 {
02114        tlsm_ctx *ctx = (tlsm_ctx *)lo->ldo_tls_ctx;
02115        ctx->tc_config = tlsm_copy_config(lt);
02116        ctx->tc_is_server = is_server;
02117 
02118        return 0;
02119 }
02120 
02121 static int
02122 tlsm_deferred_ctx_init( void *arg )
02123 {
02124        tlsm_ctx *ctx = (tlsm_ctx *)arg;
02125        PRBool sslv2 = PR_FALSE;
02126        PRBool sslv3 = PR_TRUE;
02127        PRBool tlsv1 = PR_TRUE;
02128        PRBool request_cert = PR_FALSE;
02129        PRInt32 require_cert = PR_FALSE;
02130        PRFileDesc *fd;
02131        struct ldaptls *lt;
02132 
02133        if ( tlsm_deferred_init( ctx ) ) {
02134            Debug( LDAP_DEBUG_ANY,
02135                         "TLS: could not perform TLS system initialization.\n",
02136                         0, 0, 0 );
02137            return -1;
02138        }
02139 
02140        ctx->tc_certdb = CERT_GetDefaultCertDB(); /* If there is ever a per-context db, change this */
02141 
02142        fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
02143        if ( fd ) {
02144               ctx->tc_model = SSL_ImportFD( NULL, fd );
02145        }
02146 
02147        if ( !ctx->tc_model ) {
02148               PRErrorCode err = PR_GetError();
02149               Debug( LDAP_DEBUG_ANY,
02150                         "TLS: could perform TLS socket I/O layer initialization - error %d:%s.\n",
02151                         err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
02152 
02153               if ( fd ) {
02154                      PR_Close( fd );
02155               }
02156               return -1;
02157        }
02158 
02159        if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_SECURITY, PR_TRUE ) ) {
02160               Debug( LDAP_DEBUG_ANY,
02161                      "TLS: could not set secure mode on.\n",
02162                      0, 0, 0 );
02163               return -1;
02164        }
02165 
02166        lt = ctx->tc_config;
02167 
02168        /* default is sslv3 and tlsv1 */
02169        if ( lt->lt_protocol_min ) {
02170               if ( lt->lt_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 ) {
02171                      sslv3 = PR_FALSE;
02172               } else if ( lt->lt_protocol_min <= LDAP_OPT_X_TLS_PROTOCOL_SSL2 ) {
02173                      sslv2 = PR_TRUE;
02174                      Debug( LDAP_DEBUG_ANY,
02175                             "TLS: warning: minimum TLS protocol level set to "
02176                             "include SSLv2 - SSLv2 is insecure - do not use\n", 0, 0, 0 );
02177               }
02178        }
02179        if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL2, sslv2 ) ) {
02180               Debug( LDAP_DEBUG_ANY,
02181                      "TLS: could not set SSLv2 mode on.\n",
02182                      0, 0, 0 );
02183               return -1;
02184        }
02185        if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL3, sslv3 ) ) {
02186               Debug( LDAP_DEBUG_ANY,
02187                      "TLS: could not set SSLv3 mode on.\n",
02188                      0, 0, 0 );
02189               return -1;
02190        }
02191        if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_TLS, tlsv1 ) ) {
02192               Debug( LDAP_DEBUG_ANY,
02193                      "TLS: could not set TLSv1 mode on.\n",
02194                      0, 0, 0 );
02195               return -1;
02196        }
02197 
02198        if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_CLIENT, !ctx->tc_is_server ) ) {
02199               Debug( LDAP_DEBUG_ANY,
02200                      "TLS: could not set handshake as client.\n",
02201                      0, 0, 0 );
02202               return -1;
02203        }
02204        if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_SERVER, ctx->tc_is_server ) ) {
02205               Debug( LDAP_DEBUG_ANY,
02206                      "TLS: could not set handshake as server.\n",
02207                      0, 0, 0 );
02208               return -1;
02209        }
02210 
02211        if ( lt->lt_ciphersuite &&
02212             tlsm_parse_ciphers( ctx, lt->lt_ciphersuite )) {
02213               Debug( LDAP_DEBUG_ANY,
02214                      "TLS: could not set cipher list %s.\n",
02215                      lt->lt_ciphersuite, 0, 0 );
02216               return -1;
02217        } else if ( tlsm_parse_ciphers( ctx, "DEFAULT" ) ) {
02218               Debug( LDAP_DEBUG_ANY,
02219                      "TLS: could not set cipher list DEFAULT.\n",
02220                      0, 0, 0 );
02221               return -1;
02222        }
02223 
02224        if ( !ctx->tc_require_cert ) {
02225               ctx->tc_verify_cert = PR_FALSE;
02226        } else if ( !ctx->tc_is_server ) {
02227               request_cert = PR_TRUE;
02228               require_cert = SSL_REQUIRE_NO_ERROR;
02229               if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
02230                    ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
02231                      require_cert = SSL_REQUIRE_ALWAYS;
02232               }
02233               if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW )
02234                      ctx->tc_verify_cert = PR_TRUE;
02235        } else { /* server */
02236               /* server does not request certs by default */
02237               /* if allow - client may send cert, server will ignore if errors */
02238               /* if try - client may send cert, server will error if bad cert */
02239               /* if hard or demand - client must send cert, server will error if bad cert */
02240               request_cert = PR_TRUE;
02241               require_cert = SSL_REQUIRE_NO_ERROR;
02242               if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
02243                    ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
02244                      require_cert = SSL_REQUIRE_ALWAYS;
02245               }
02246               if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW ) {
02247                      ctx->tc_verify_cert = PR_TRUE;
02248               } else {
02249                      ctx->tc_warn_only = PR_TRUE;
02250               }
02251        }
02252 
02253        if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUEST_CERTIFICATE, request_cert ) ) {
02254               Debug( LDAP_DEBUG_ANY,
02255                      "TLS: could not set request certificate mode.\n",
02256                      0, 0, 0 );
02257               return -1;
02258        }
02259               
02260        if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUIRE_CERTIFICATE, require_cert ) ) {
02261               Debug( LDAP_DEBUG_ANY,
02262                      "TLS: could not set require certificate mode.\n",
02263                      0, 0, 0 );
02264               return -1;
02265        }
02266 
02267        /* set up our cert and key, if any */
02268        if ( lt->lt_certfile ) {
02269               /* if using the PEM module, load the PEM file specified by lt_certfile */
02270               /* otherwise, assume this is the name of a cert already in the db */
02271               if ( ctx->tc_using_pem ) {
02272                      /* this sets ctx->tc_certname to the correct value */
02273                      int rc = tlsm_add_cert_from_file( ctx, lt->lt_certfile, PR_FALSE, PR_TRUE );
02274                      if ( rc ) {
02275                             return rc;
02276                      }
02277               } else {
02278                      PL_strfree( ctx->tc_certname );
02279                      ctx->tc_certname = PL_strdup( lt->lt_certfile );
02280               }
02281        }
02282 
02283        if ( lt->lt_keyfile ) {
02284               /* if using the PEM module, load the PEM file specified by lt_keyfile */
02285               /* otherwise, assume this is the pininfo for the key */
02286               if ( ctx->tc_using_pem ) {
02287                      /* this sets ctx->tc_certname to the correct value */
02288                      int rc = tlsm_add_key_from_file( ctx, lt->lt_keyfile );
02289                      if ( rc ) {
02290                             return rc;
02291                      }
02292               } else {
02293                      PL_strfree( ctx->tc_pin_file );
02294                      ctx->tc_pin_file = PL_strdup( lt->lt_keyfile );
02295               }
02296        }
02297 
02298        /* Set up callbacks for use by clients */
02299        if ( !ctx->tc_is_server ) {
02300               if ( SSL_OptionSet( ctx->tc_model, SSL_NO_CACHE, PR_TRUE ) != SECSuccess ) {
02301                      PRErrorCode err = PR_GetError();
02302                      Debug( LDAP_DEBUG_ANY, 
02303                             "TLS: error: could not set nocache option for moznss - error %d:%s\n",
02304                             err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
02305                      return -1;
02306               }
02307 
02308               if ( SSL_BadCertHook( ctx->tc_model, tlsm_bad_cert_handler, ctx ) != SECSuccess ) {
02309                      PRErrorCode err = PR_GetError();
02310                      Debug( LDAP_DEBUG_ANY, 
02311                             "TLS: error: could not set bad cert handler for moznss - error %d:%s\n",
02312                             err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
02313                      return -1;
02314               }
02315 
02316               /* 
02317                  since a cert has been specified, assume the client wants to do cert auth
02318               */
02319               if ( ctx->tc_certname ) {
02320                      if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
02321                             Debug( LDAP_DEBUG_ANY, 
02322                                    "TLS: error: unable to authenticate to the security device for certificate %s\n",
02323                                    ctx->tc_certname, 0, 0 );
02324                             return -1;
02325                      }
02326                      if ( tlsm_clientauth_init( ctx ) ) {
02327                             Debug( LDAP_DEBUG_ANY, 
02328                                    "TLS: error: unable to set up client certificate authentication using %s\n",
02329                                    ctx->tc_certname, 0, 0 );
02330                             return -1;
02331                      }
02332               }
02333        } else { /* set up secure server */
02334               SSLKEAType certKEA;
02335               CERTCertificate *serverCert = NULL;
02336               SECKEYPrivateKey *serverKey = NULL;
02337               SECStatus status;
02338 
02339               /* must have a certificate for the server to use */
02340               if ( !ctx->tc_certname ) {
02341                      Debug( LDAP_DEBUG_ANY, 
02342                             "TLS: error: no server certificate: must specify a certificate for the server to use\n",
02343                             0, 0, 0 );
02344                      return -1;
02345               }
02346 
02347               /* authenticate to the server's token - this will do nothing
02348                  if the key/cert db is not password protected */
02349               if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
02350                      Debug( LDAP_DEBUG_ANY, 
02351                             "TLS: error: unable to authenticate to the security device for certificate %s\n",
02352                             ctx->tc_certname, 0, 0 );
02353                      return -1;
02354               }
02355 
02356               /* get the server's key and cert */
02357               if ( tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, ctx->tc_is_server,
02358                                               &serverCert, &serverKey ) ) {
02359                      Debug( LDAP_DEBUG_ANY, 
02360                             "TLS: error: unable to find and verify server's cert and key for certificate %s\n",
02361                             ctx->tc_certname, 0, 0 );
02362                      CERT_DestroyCertificate( serverCert );
02363                      SECKEY_DestroyPrivateKey( serverKey );
02364                      return -1;
02365               }
02366 
02367               certKEA = NSS_FindCertKEAType( serverCert );
02368               /* configure the socket to be a secure server socket */
02369               status = SSL_ConfigSecureServer( ctx->tc_model, serverCert, serverKey, certKEA );
02370               /* SSL_ConfigSecureServer copies these */
02371               CERT_DestroyCertificate( serverCert );
02372               SECKEY_DestroyPrivateKey( serverKey );
02373 
02374               if ( SECSuccess != status ) {
02375                      PRErrorCode err = PR_GetError();
02376                      Debug( LDAP_DEBUG_ANY, 
02377                             "TLS: error: unable to configure secure server using certificate %s - error %d:%s\n",
02378                             ctx->tc_certname, err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
02379                      return -1;
02380               }
02381        }
02382 
02383        /* Callback for authenticating certificate */
02384        if ( SSL_AuthCertificateHook( ctx->tc_model, tlsm_auth_cert_handler,
02385                                   ctx ) != SECSuccess ) {
02386               PRErrorCode err = PR_GetError();
02387               Debug( LDAP_DEBUG_ANY, 
02388                      "TLS: error: could not set auth cert handler for moznss - error %d:%s\n",
02389                      err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
02390               return -1;
02391        }
02392 
02393        if ( SSL_HandshakeCallback( ctx->tc_model, tlsm_handshake_complete_cb, ctx ) ) {
02394               PRErrorCode err = PR_GetError();
02395               Debug( LDAP_DEBUG_ANY, 
02396                      "TLS: error: could not set handshake callback for moznss - error %d:%s\n",
02397                      err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
02398               return -1;
02399        }
02400 
02401        tlsm_free_config( ctx->tc_config );
02402        ctx->tc_config = NULL;
02403 
02404        return 0;
02405 }
02406 
02407 struct tls_data {
02408        tlsm_session         *session;
02409        Sockbuf_IO_Desc             *sbiod;
02410        /* there seems to be no portable way to determine if the
02411           sockbuf sd has been set to nonblocking mode - the
02412           call to ber_pvt_socket_set_nonblock() takes place
02413           before the tls socket is set up, so we cannot
02414           intercept that call either.
02415           On systems where fcntl is available, we can just
02416           F_GETFL and test for O_NONBLOCK.  On other systems,
02417           we will just see if the IO op returns EAGAIN or EWOULDBLOCK,
02418           and just set this flag */
02419        PRBool              nonblock;
02420        /*
02421         * NSS tries hard to be backwards compatible with SSLv2 clients, or
02422         * clients that send an SSLv2 client hello.  This message is not
02423         * tagged in any way, so NSS has no way to know if the incoming
02424         * message is a valid SSLv2 client hello or just some bogus data
02425         * (or cleartext LDAP).  We store the first byte read from the
02426         * client here.  The most common case will be a client sending
02427         * LDAP data instead of SSL encrypted LDAP data.  This can happen,
02428         * for example, if using ldapsearch -Z - if the starttls fails,
02429         * the client will fallback to plain cleartext LDAP.  So if we
02430         * see that the firstbyte is a valid LDAP tag, we can be
02431         * pretty sure this is happening.
02432         */
02433        ber_tag_t           firsttag;
02434        /*
02435         * NSS doesn't return SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, etc.
02436         * when it is blocked, so we have to set a flag in the wrapped send
02437         * and recv calls that tells us what operation NSS was last blocked
02438         * on
02439         */
02440 #define TLSM_READ  1
02441 #define TLSM_WRITE 2
02442        int io_flag;
02443 };
02444 
02445 static struct tls_data *
02446 tlsm_get_pvt_tls_data( PRFileDesc *fd )
02447 {
02448        struct tls_data             *p;
02449        PRFileDesc *myfd;
02450 
02451        if ( !fd ) {
02452               return NULL;
02453        }
02454 
02455        myfd = PR_GetIdentitiesLayer( fd, tlsm_layer_id );
02456 
02457        if ( !myfd ) {
02458               return NULL;
02459        }
02460 
02461        p = (struct tls_data *)myfd->secret;
02462 
02463        return p;
02464 }
02465 
02466 static int
02467 tlsm_is_non_ssl_message( PRFileDesc *fd, ber_tag_t *thebyte )
02468 {
02469        struct tls_data             *p;
02470 
02471        if ( thebyte ) {
02472               *thebyte = LBER_DEFAULT;
02473        }
02474 
02475        p = tlsm_get_pvt_tls_data( fd );
02476        if ( p == NULL || p->sbiod == NULL ) {
02477               return 0;
02478        }
02479 
02480        if ( p->firsttag == LBER_SEQUENCE ) {
02481               if ( thebyte ) {
02482                      *thebyte = p->firsttag;
02483               }
02484               return 1;
02485        }
02486 
02487        return 0;
02488 }
02489 
02490 static tls_session *
02491 tlsm_session_new ( tls_ctx * ctx, int is_server )
02492 {
02493        tlsm_ctx *c = (tlsm_ctx *)ctx;
02494        tlsm_session *session;
02495        PRFileDesc *fd;
02496        PRStatus status;
02497        int rc;
02498 
02499        c->tc_is_server = is_server;
02500        status = PR_CallOnceWithArg( &c->tc_callonce, tlsm_deferred_ctx_init, c );
02501        if ( PR_SUCCESS != status ) {
02502               PRErrorCode err = PR_GetError();
02503               Debug( LDAP_DEBUG_ANY, 
02504                      "TLS: error: could not initialize moznss security context - error %d:%s\n",
02505                      err, PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT), NULL );
02506               return NULL;
02507        }
02508 
02509        fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
02510        if ( !fd ) {
02511               return NULL;
02512        }
02513 
02514        session = SSL_ImportFD( c->tc_model, fd );
02515        if ( !session ) {
02516               PR_DELETE( fd );
02517               return NULL;
02518        }
02519 
02520        rc = SSL_ResetHandshake( session, is_server );
02521        if ( rc ) {
02522               PRErrorCode err = PR_GetError();
02523               Debug( LDAP_DEBUG_TRACE, 
02524                         "TLS: error: new session - reset handshake failure %d - error %d:%s\n",
02525                         rc, err,
02526                         err ? PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) : "unknown" );
02527               PR_DELETE( fd );
02528               PR_Close( session );
02529               session = NULL;
02530        }
02531 
02532        return (tls_session *)session;
02533 } 
02534 
02535 static int
02536 tlsm_session_accept_or_connect( tls_session *session, int is_accept )
02537 {
02538        tlsm_session *s = (tlsm_session *)session;
02539        int rc;
02540        const char *op = is_accept ? "accept" : "connect";
02541 
02542        if ( pem_module ) {
02543               LDAP_MUTEX_LOCK( &tlsm_pem_mutex );
02544        }
02545        rc = SSL_ForceHandshake( s );
02546        if ( pem_module ) {
02547               LDAP_MUTEX_UNLOCK( &tlsm_pem_mutex );
02548        }
02549        if ( rc ) {
02550               PRErrorCode err = PR_GetError();
02551               rc = -1;
02552               if ( err == PR_WOULD_BLOCK_ERROR ) {
02553                      ber_tag_t thetag = LBER_DEFAULT;
02554                      /* see if we are blocked because of a bogus packet */
02555                      if ( tlsm_is_non_ssl_message( s, &thetag ) ) { /* see if we received a non-SSL message */
02556                             Debug( LDAP_DEBUG_ANY, 
02557                                       "TLS: error: %s - error - received non-SSL message [0x%x]\n",
02558                                       op, (unsigned int)thetag, 0 );
02559                             /* reset error to something more descriptive */
02560                             PR_SetError( SSL_ERROR_RX_MALFORMED_HELLO_REQUEST, EPROTO );
02561                      }
02562               } else {
02563                      Debug( LDAP_DEBUG_ANY, 
02564                                "TLS: error: %s - force handshake failure: errno %d - moznss error %d\n",
02565                                op, errno, err );
02566               }
02567        }
02568 
02569        return rc;
02570 }
02571 static int
02572 tlsm_session_accept( tls_session *session )
02573 {
02574        return tlsm_session_accept_or_connect( session, 1 );
02575 }
02576 
02577 static int
02578 tlsm_session_connect( LDAP *ld, tls_session *session )
02579 {
02580        return tlsm_session_accept_or_connect( session, 0 );
02581 }
02582 
02583 static int
02584 tlsm_session_upflags( Sockbuf *sb, tls_session *session, int rc )
02585 {
02586        int prerror = PR_GetError();
02587 
02588        if ( ( prerror == PR_PENDING_INTERRUPT_ERROR ) || ( prerror == PR_WOULD_BLOCK_ERROR ) ) {
02589               tlsm_session *s = (tlsm_session *)session;
02590               struct tls_data *p = tlsm_get_pvt_tls_data( s );
02591 
02592               if ( p && ( p->io_flag == TLSM_READ ) ) {
02593                      sb->sb_trans_needs_read = 1;
02594                      return 1;
02595               } else if ( p && ( p->io_flag == TLSM_WRITE ) ) {
02596                      sb->sb_trans_needs_write = 1;
02597                      return 1;
02598               }
02599        }
02600 
02601        return 0;
02602 }
02603 
02604 static char *
02605 tlsm_session_errmsg( tls_session *sess, int rc, char *buf, size_t len )
02606 {
02607        int i;
02608        int prerror = PR_GetError();
02609 
02610        i = PR_GetErrorTextLength();
02611        if ( i > len ) {
02612               char *msg = LDAP_MALLOC( i+1 );
02613               PR_GetErrorText( msg );
02614               memcpy( buf, msg, len );
02615               LDAP_FREE( msg );
02616        } else if ( i ) {
02617               PR_GetErrorText( buf );
02618        } else if ( prerror ) {
02619               i = PR_snprintf( buf, len, "TLS error %d:%s",
02620                                            prerror, PR_ErrorToString( prerror, PR_LANGUAGE_I_DEFAULT ) );
02621        }
02622 
02623        return ( i > 0 ) ? buf : NULL;
02624 }
02625 
02626 static int
02627 tlsm_session_my_dn( tls_session *session, struct berval *der_dn )
02628 {
02629        tlsm_session *s = (tlsm_session *)session;
02630        CERTCertificate *cert;
02631 
02632        cert = SSL_LocalCertificate( s );
02633        if (!cert) return LDAP_INVALID_CREDENTIALS;
02634 
02635        der_dn->bv_val = (char *)cert->derSubject.data;
02636        der_dn->bv_len = cert->derSubject.len;
02637        CERT_DestroyCertificate( cert );
02638        return 0;
02639 }
02640 
02641 static int
02642 tlsm_session_peer_dn( tls_session *session, struct berval *der_dn )
02643 {
02644        tlsm_session *s = (tlsm_session *)session;
02645        CERTCertificate *cert;
02646 
02647        cert = SSL_PeerCertificate( s );
02648        if (!cert) return LDAP_INVALID_CREDENTIALS;
02649        
02650        der_dn->bv_val = (char *)cert->derSubject.data;
02651        der_dn->bv_len = cert->derSubject.len;
02652        CERT_DestroyCertificate( cert );
02653        return 0;
02654 }
02655 
02656 /* what kind of hostname were we given? */
02657 #define       IS_DNS 0
02658 #define       IS_IP4 1
02659 #define       IS_IP6 2
02660 
02661 static int
02662 tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
02663 {
02664        tlsm_session *s = (tlsm_session *)session;
02665        CERTCertificate *cert;
02666        const char *name, *domain = NULL, *ptr;
02667        int ret, ntype = IS_DNS, nlen, dlen;
02668 #ifdef LDAP_PF_INET6
02669        struct in6_addr addr;
02670 #else
02671        struct in_addr addr;
02672 #endif
02673        SECItem altname;
02674        SECStatus rv;
02675 
02676        if( ldap_int_hostname &&
02677               ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
02678        {
02679               name = ldap_int_hostname;
02680        } else {
02681               name = name_in;
02682        }
02683        nlen = strlen( name );
02684 
02685        cert = SSL_PeerCertificate( s );
02686        if (!cert) {
02687               Debug( LDAP_DEBUG_ANY,
02688                      "TLS: unable to get peer certificate.\n",
02689                      0, 0, 0 );
02690               /* if this was a fatal condition, things would have
02691                * aborted long before now.
02692                */
02693               return LDAP_SUCCESS;
02694        }
02695 
02696 #ifdef LDAP_PF_INET6
02697        if (inet_pton(AF_INET6, name, &addr)) {
02698               ntype = IS_IP6;
02699        } else 
02700 #endif
02701        if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
02702               if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
02703        }
02704        if (ntype == IS_DNS ) {
02705               domain = strchr( name, '.' );
02706               if ( domain )
02707                      dlen = nlen - ( domain - name );
02708        }
02709 
02710        ret = LDAP_LOCAL_ERROR;
02711 
02712        rv = CERT_FindCertExtension( cert, SEC_OID_X509_SUBJECT_ALT_NAME,
02713               &altname );
02714        if ( rv == SECSuccess && altname.data ) {
02715               PRArenaPool *arena;
02716               CERTGeneralName *names, *cur;
02717 
02718               arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02719               if ( !arena ) {
02720                      ret = LDAP_NO_MEMORY;
02721                      goto fail;
02722               }
02723 
02724               names = cur = CERT_DecodeAltNameExtension(arena, &altname);
02725               if ( !cur )
02726                      goto altfail;
02727 
02728               do {
02729                      char *host;
02730                      int hlen;
02731 
02732                      /* ignore empty */
02733                      if ( !cur->name.other.len ) continue;
02734 
02735                      host = (char *)cur->name.other.data;
02736                      hlen = cur->name.other.len;
02737 
02738                      if ( cur->type == certDNSName ) {
02739                             if ( ntype != IS_DNS )      continue;
02740 
02741                             /* is this an exact match? */
02742                             if ( nlen == hlen && !strncasecmp( name, host, nlen )) {
02743                                    ret = LDAP_SUCCESS;
02744                                    break;
02745                             }
02746 
02747                             /* is this a wildcard match? */
02748                             if ( domain && host[0] == '*' && host[1] == '.' &&
02749                                    dlen == hlen-1 && !strncasecmp( domain, host+1, dlen )) {
02750                                    ret = LDAP_SUCCESS;
02751                                    break;
02752                             }
02753                      } else if ( cur->type == certIPAddress ) {
02754                             if ( ntype == IS_DNS )      continue;
02755                             
02756 #ifdef LDAP_PF_INET6
02757                             if (ntype == IS_IP6 && hlen != sizeof(struct in6_addr)) {
02758                                    continue;
02759                             } else
02760 #endif
02761                             if (ntype == IS_IP4 && hlen != sizeof(struct in_addr)) {
02762                                    continue;
02763                             }
02764                             if (!memcmp(host, &addr, hlen)) {
02765                                    ret = LDAP_SUCCESS;
02766                                    break;
02767                             }
02768                      }
02769               } while (( cur = CERT_GetNextGeneralName( cur )) != names );
02770 altfail:
02771               PORT_FreeArena( arena, PR_FALSE );
02772               SECITEM_FreeItem( &altname, PR_FALSE );
02773        }
02774        /* no altnames matched, try the CN */
02775        if ( ret != LDAP_SUCCESS ) {
02776               /* find the last CN */
02777               CERTRDN *rdn, **rdns;
02778               CERTAVA *lastava = NULL;
02779               char buf[2048];
02780 
02781               buf[0] = '\0';
02782               rdns = cert->subject.rdns;
02783               while ( rdns && ( rdn = *rdns++ )) {
02784                      CERTAVA *ava, **avas = rdn->avas;
02785                      while ( avas && ( ava = *avas++ )) {
02786                             if ( CERT_GetAVATag( ava ) == SEC_OID_AVA_COMMON_NAME )
02787                                    lastava = ava;
02788                      }
02789               }
02790               if ( lastava ) {
02791                      SECItem *av = CERT_DecodeAVAValue( &lastava->value );
02792                      if ( av ) {
02793                             if ( av->len == nlen && !strncasecmp( name, (char *)av->data, nlen )) {
02794                                    ret = LDAP_SUCCESS;
02795                             } else if ( av->data[0] == '*' && av->data[1] == '.' &&
02796                                    domain && dlen == av->len - 1 && !strncasecmp( domain,
02797                                           (char *)(av->data+1), dlen )) {
02798                                    ret = LDAP_SUCCESS;
02799                             } else {
02800                                    int len = av->len;
02801                                    if ( len >= sizeof(buf) )
02802                                           len = sizeof(buf)-1;
02803                                    memcpy( buf, av->data, len );
02804                                    buf[len] = '\0';
02805                             }
02806                             SECITEM_FreeItem( av, PR_TRUE );
02807                      }
02808               }
02809               if ( ret != LDAP_SUCCESS ) {
02810                      Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
02811                             "common name in certificate (%s).\n", 
02812                             name, buf, 0 );
02813                      ret = LDAP_CONNECT_ERROR;
02814                      if ( ld->ld_error ) {
02815                             LDAP_FREE( ld->ld_error );
02816                      }
02817                      ld->ld_error = LDAP_STRDUP(
02818                             _("TLS: hostname does not match CN in peer certificate"));
02819               }
02820        }
02821 
02822 fail:
02823        CERT_DestroyCertificate( cert );
02824        return ret;
02825 }
02826 
02827 static int
02828 tlsm_session_strength( tls_session *session )
02829 {
02830        tlsm_session *s = (tlsm_session *)session;
02831        int rc, keySize;
02832 
02833        rc = SSL_SecurityStatus( s, NULL, NULL, NULL, &keySize,
02834               NULL, NULL );
02835        return rc ? 0 : keySize;
02836 }
02837 
02838 /*
02839  * TLS support for LBER Sockbufs
02840  */
02841 
02842 static PRStatus PR_CALLBACK
02843 tlsm_PR_Close(PRFileDesc *fd)
02844 {
02845        int rc = PR_SUCCESS;
02846 
02847        /* we don't need to actually close anything here, just
02848           pop our io layer off the stack */
02849        fd->secret = NULL; /* must have been freed before calling PR_Close */
02850        if ( fd->lower ) {
02851               fd = PR_PopIOLayer( fd, tlsm_layer_id );
02852               /* if we are not the last layer, pass the close along */
02853               if ( fd ) {
02854                      if ( fd->dtor ) {
02855                             fd->dtor( fd );
02856                      }
02857                      rc = fd->methods->close( fd );
02858               }
02859        } else {
02860               /* we are the last layer - just call our dtor */
02861               fd->dtor(fd);
02862        }
02863 
02864        return rc;
02865 }
02866 
02867 static PRStatus PR_CALLBACK
02868 tlsm_PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
02869 {
02870        int rc = PR_SUCCESS;
02871 
02872        if ( fd->lower ) {
02873               rc = PR_Shutdown( fd->lower, how );
02874        }
02875 
02876        return rc;
02877 }
02878 
02879 static int PR_CALLBACK
02880 tlsm_PR_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags,
02881         PRIntervalTime timeout)
02882 {
02883        struct tls_data             *p;
02884        int rc;
02885 
02886        if ( buf == NULL || len <= 0 ) return 0;
02887 
02888        p = tlsm_get_pvt_tls_data( fd );
02889 
02890        if ( p == NULL || p->sbiod == NULL ) {
02891               return 0;
02892        }
02893 
02894        rc = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
02895        if (rc <= 0) {
02896               tlsm_map_error( errno );
02897               if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
02898                      p->nonblock = PR_TRUE; /* fd is using non-blocking io */
02899               } else if ( errno ) { /* real error */
02900                      Debug( LDAP_DEBUG_TRACE, 
02901                             "TLS: error: tlsm_PR_Recv returned %d - error %d:%s\n",
02902                             rc, errno, STRERROR(errno) );
02903               }
02904        } else if ( ( rc > 0 ) && ( len > 0 ) && ( p->firsttag == LBER_DEFAULT ) ) {
02905               p->firsttag = (ber_tag_t)*((char *)buf);
02906        }
02907        p->io_flag = TLSM_READ;
02908 
02909        return rc;
02910 }
02911 
02912 static int PR_CALLBACK
02913 tlsm_PR_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags,
02914         PRIntervalTime timeout)
02915 {
02916        struct tls_data             *p;
02917        int rc;
02918 
02919        if ( buf == NULL || len <= 0 ) return 0;
02920 
02921        p = tlsm_get_pvt_tls_data( fd );
02922 
02923        if ( p == NULL || p->sbiod == NULL ) {
02924               return 0;
02925        }
02926 
02927        rc = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
02928        if (rc <= 0) {
02929               tlsm_map_error( errno );
02930               if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
02931                      p->nonblock = PR_TRUE;
02932               } else if ( errno ) { /* real error */
02933                      Debug( LDAP_DEBUG_TRACE, 
02934                             "TLS: error: tlsm_PR_Send returned %d - error %d:%s\n",
02935                             rc, errno, STRERROR(errno) );
02936               }
02937        }
02938        p->io_flag = TLSM_WRITE;
02939 
02940        return rc;
02941 }
02942 
02943 static int PR_CALLBACK
02944 tlsm_PR_Read(PRFileDesc *fd, void *buf, PRInt32 len)
02945 {
02946        return tlsm_PR_Recv( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
02947 }
02948 
02949 static int PR_CALLBACK
02950 tlsm_PR_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
02951 {
02952        return tlsm_PR_Send( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
02953 }
02954 
02955 static PRStatus PR_CALLBACK
02956 tlsm_PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
02957 {
02958        struct tls_data             *p;
02959        ber_socklen_t len;
02960 
02961        p = tlsm_get_pvt_tls_data( fd );
02962 
02963        if ( p == NULL || p->sbiod == NULL ) {
02964               return PR_FAILURE;
02965        }
02966        len = sizeof(PRNetAddr);
02967        return getpeername( p->sbiod->sbiod_sb->sb_fd, (struct sockaddr *)addr, &len );
02968 }
02969 
02970 static PRStatus PR_CALLBACK
02971 tlsm_PR_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
02972 {
02973        struct tls_data             *p;
02974        p = tlsm_get_pvt_tls_data( fd );
02975 
02976        if ( p == NULL || data == NULL ) {
02977               return PR_FAILURE;
02978        }
02979 
02980        /* only the nonblocking option is supported at this time
02981           MozNSS SSL code needs it */
02982        if ( data->option != PR_SockOpt_Nonblocking ) {
02983               PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
02984               return PR_FAILURE;
02985        }
02986 #ifdef HAVE_FCNTL
02987        int flags = fcntl( p->sbiod->sbiod_sb->sb_fd, F_GETFL );
02988        data->value.non_blocking = (flags & O_NONBLOCK) ? PR_TRUE : PR_FALSE;        
02989 #else /* punt :P */
02990        data->value.non_blocking = p->nonblock;
02991 #endif
02992        return PR_SUCCESS;
02993 }
02994 
02995 static PRStatus PR_CALLBACK
02996 tlsm_PR_prs_unimp()
02997 {
02998     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
02999     return PR_FAILURE;
03000 }
03001 
03002 static PRFileDesc * PR_CALLBACK
03003 tlsm_PR_pfd_unimp()
03004 {
03005     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
03006     return NULL;
03007 }
03008 
03009 static PRInt16 PR_CALLBACK
03010 tlsm_PR_i16_unimp()
03011 {
03012     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
03013     return SECFailure;
03014 }
03015 
03016 static PRInt32 PR_CALLBACK
03017 tlsm_PR_i32_unimp()
03018 {
03019     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
03020     return SECFailure;
03021 }
03022 
03023 static PRInt64 PR_CALLBACK
03024 tlsm_PR_i64_unimp()
03025 {
03026     PRInt64 res;
03027 
03028     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
03029     LL_I2L(res, -1L);
03030     return res;
03031 }
03032 
03033 static const PRIOMethods tlsm_PR_methods = {
03034     PR_DESC_LAYERED,
03035     tlsm_PR_Close,                 /* close        */
03036     tlsm_PR_Read,                  /* read         */
03037     tlsm_PR_Write,                 /* write        */
03038     tlsm_PR_i32_unimp,             /* available    */
03039     tlsm_PR_i64_unimp,             /* available64  */
03040     tlsm_PR_prs_unimp,             /* fsync        */
03041     tlsm_PR_i32_unimp,             /* seek         */
03042     tlsm_PR_i64_unimp,             /* seek64       */
03043     tlsm_PR_prs_unimp,             /* fileInfo     */
03044     tlsm_PR_prs_unimp,             /* fileInfo64   */
03045     tlsm_PR_i32_unimp,             /* writev       */
03046     tlsm_PR_prs_unimp,             /* connect      */
03047     tlsm_PR_pfd_unimp,             /* accept       */
03048     tlsm_PR_prs_unimp,             /* bind         */
03049     tlsm_PR_prs_unimp,             /* listen       */
03050     (PRShutdownFN)tlsm_PR_Shutdown,                     /* shutdown     */
03051     tlsm_PR_Recv,                  /* recv         */
03052     tlsm_PR_Send,                  /* send         */
03053     tlsm_PR_i32_unimp,             /* recvfrom     */
03054     tlsm_PR_i32_unimp,             /* sendto       */
03055     (PRPollFN)tlsm_PR_i16_unimp,   /* poll         */
03056     tlsm_PR_i32_unimp,             /* acceptread   */
03057     tlsm_PR_i32_unimp,             /* transmitfile */
03058     tlsm_PR_prs_unimp,             /* getsockname  */
03059     tlsm_PR_GetPeerName,    /* getpeername  */
03060     tlsm_PR_i32_unimp,             /* getsockopt   OBSOLETE */
03061     tlsm_PR_i32_unimp,             /* setsockopt   OBSOLETE */
03062     tlsm_PR_GetSocketOption,              /* getsocketoption   */
03063     tlsm_PR_i32_unimp,             /* setsocketoption   */
03064     tlsm_PR_i32_unimp,             /* Send a (partial) file with header/trailer*/
03065     (PRConnectcontinueFN)tlsm_PR_prs_unimp,             /* connectcontinue */
03066     tlsm_PR_i32_unimp,             /* reserved for future use */
03067     tlsm_PR_i32_unimp,             /* reserved for future use */
03068     tlsm_PR_i32_unimp,             /* reserved for future use */
03069     tlsm_PR_i32_unimp              /* reserved for future use */
03070 };
03071 
03072 /*
03073  * Initialize TLS subsystem. Should be called only once.
03074  * See tlsm_deferred_init for the bulk of the init process
03075  */
03076 static int
03077 tlsm_init( void )
03078 {
03079        char *nofork = PR_GetEnv( "NSS_STRICT_NOFORK" );
03080 
03081        PR_Init(0, 0, 0);
03082 
03083        tlsm_layer_id = PR_GetUniqueIdentity( "OpenLDAP" );
03084 
03085        /*
03086         * There are some applications that acquire a crypto context in the parent process
03087         * and expect that crypto context to work after a fork().  This does not work
03088         * with NSS using strict PKCS11 compliance mode.  We set this environment
03089         * variable here to tell the software encryption module/token to allow crypto
03090         * contexts to persist across a fork().  However, if you are using some other
03091         * module or encryption device that supports and expects full PKCS11 semantics,
03092         * the only recourse is to rewrite the application with atfork() handlers to save
03093         * the crypto context in the parent and restore (and SECMOD_RestartModules) the
03094         * context in the child.
03095         */
03096        if ( !nofork ) {
03097               /* will leak one time */
03098               char *noforkenvvar = PL_strdup( "NSS_STRICT_NOFORK=DISABLED" );
03099               PR_SetEnv( noforkenvvar );
03100        }
03101 
03102        return 0;
03103 }
03104 
03105 static int
03106 tlsm_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
03107 {
03108        struct tls_data             *p;
03109        tlsm_session  *session = arg;
03110        PRFileDesc *fd;
03111 
03112        assert( sbiod != NULL );
03113 
03114        p = LBER_MALLOC( sizeof( *p ) );
03115        if ( p == NULL ) {
03116               return -1;
03117        }
03118 
03119        fd = PR_GetIdentitiesLayer( session, tlsm_layer_id );
03120        if ( !fd ) {
03121               LBER_FREE( p );
03122               return -1;
03123        }
03124 
03125        fd->secret = (PRFilePrivate *)p;
03126        p->session = session;
03127        p->sbiod = sbiod;
03128        p->firsttag = LBER_DEFAULT;
03129        sbiod->sbiod_pvt = p;
03130        return 0;
03131 }
03132 
03133 static int
03134 tlsm_sb_remove( Sockbuf_IO_Desc *sbiod )
03135 {
03136        struct tls_data             *p;
03137        
03138        assert( sbiod != NULL );
03139        assert( sbiod->sbiod_pvt != NULL );
03140 
03141        p = (struct tls_data *)sbiod->sbiod_pvt;
03142        PR_Close( p->session );
03143        LBER_FREE( sbiod->sbiod_pvt );
03144        sbiod->sbiod_pvt = NULL;
03145        return 0;
03146 }
03147 
03148 static int
03149 tlsm_sb_close( Sockbuf_IO_Desc *sbiod )
03150 {
03151        struct tls_data             *p;
03152        
03153        assert( sbiod != NULL );
03154        assert( sbiod->sbiod_pvt != NULL );
03155 
03156        p = (struct tls_data *)sbiod->sbiod_pvt;
03157        PR_Shutdown( p->session, PR_SHUTDOWN_BOTH );
03158        return 0;
03159 }
03160 
03161 static int
03162 tlsm_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
03163 {
03164        struct tls_data             *p;
03165        
03166        assert( sbiod != NULL );
03167        assert( sbiod->sbiod_pvt != NULL );
03168 
03169        p = (struct tls_data *)sbiod->sbiod_pvt;
03170        
03171        if ( opt == LBER_SB_OPT_GET_SSL ) {
03172               *((tlsm_session **)arg) = p->session;
03173               return 1;
03174               
03175        } else if ( opt == LBER_SB_OPT_DATA_READY ) {
03176               if ( p && ( SSL_DataPending( p->session ) > 0 ) ) {
03177                      return 1;
03178               }
03179               
03180        }
03181        
03182        return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
03183 }
03184 
03185 static ber_slen_t
03186 tlsm_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
03187 {
03188        struct tls_data             *p;
03189        ber_slen_t           ret;
03190        int                  err;
03191 
03192        assert( sbiod != NULL );
03193        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
03194 
03195        p = (struct tls_data *)sbiod->sbiod_pvt;
03196 
03197        ret = PR_Recv( p->session, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
03198        if ( ret < 0 ) {
03199               err = PR_GetError();
03200               if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
03201                      sbiod->sbiod_sb->sb_trans_needs_read = 1;
03202                      sock_errset(EWOULDBLOCK);
03203               }
03204        } else {
03205               sbiod->sbiod_sb->sb_trans_needs_read = 0;
03206        }
03207        return ret;
03208 }
03209 
03210 static ber_slen_t
03211 tlsm_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
03212 {
03213        struct tls_data             *p;
03214        ber_slen_t           ret;
03215        int                  err;
03216 
03217        assert( sbiod != NULL );
03218        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
03219 
03220        p = (struct tls_data *)sbiod->sbiod_pvt;
03221 
03222        ret = PR_Send( p->session, (char *)buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
03223        if ( ret < 0 ) {
03224               err = PR_GetError();
03225               if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
03226                      sbiod->sbiod_sb->sb_trans_needs_write = 1;
03227                      sock_errset(EWOULDBLOCK);
03228                      ret = 0;
03229               }
03230        } else {
03231               sbiod->sbiod_sb->sb_trans_needs_write = 0;
03232        }
03233        return ret;
03234 }
03235 
03236 static Sockbuf_IO tlsm_sbio =
03237 {
03238        tlsm_sb_setup,              /* sbi_setup */
03239        tlsm_sb_remove,             /* sbi_remove */
03240        tlsm_sb_ctrl,        /* sbi_ctrl */
03241        tlsm_sb_read,        /* sbi_read */
03242        tlsm_sb_write,              /* sbi_write */
03243        tlsm_sb_close        /* sbi_close */
03244 };
03245 
03246 tls_impl ldap_int_tls_impl = {
03247        "MozNSS",
03248 
03249        tlsm_init,
03250        tlsm_destroy,
03251 
03252        tlsm_ctx_new,
03253        tlsm_ctx_ref,
03254        tlsm_ctx_free,
03255        tlsm_ctx_init,
03256 
03257        tlsm_session_new,
03258        tlsm_session_connect,
03259        tlsm_session_accept,
03260        tlsm_session_upflags,
03261        tlsm_session_errmsg,
03262        tlsm_session_my_dn,
03263        tlsm_session_peer_dn,
03264        tlsm_session_chkhost,
03265        tlsm_session_strength,
03266 
03267        &tlsm_sbio,
03268 
03269 #ifdef LDAP_R_COMPILE
03270        tlsm_thr_init,
03271 #else
03272        NULL,
03273 #endif
03274 
03275        0
03276 };
03277 
03278 #endif /* HAVE_MOZNSS */
03279 /*
03280   emacs settings
03281   Local Variables:
03282   indent-tabs-mode: t
03283   tab-width: 4
03284   End:
03285 */