]> git.sur5r.net Git - openldap/blob - libraries/libldap/tls_m.c
Merge remote-tracking branch 'origin/mdb.master'
[openldap] / libraries / libldap / tls_m.c
1 /* tls_m.c - Handle tls/ssl using Mozilla NSS. */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2008-2012 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS: Initial version written by Howard Chu. 
17  * Additional support by Rich Megginson.
18  */
19
20 #include "portable.h"
21
22 #ifdef HAVE_MOZNSS
23
24 #include "ldap_config.h"
25
26 #include <stdio.h>
27
28 #if defined( HAVE_FCNTL_H )
29 #include <fcntl.h>
30 #endif
31
32 #include <ac/stdlib.h>
33 #include <ac/errno.h>
34 #include <ac/socket.h>
35 #include <ac/string.h>
36 #include <ac/ctype.h>
37 #include <ac/time.h>
38 #include <ac/unistd.h>
39 #include <ac/param.h>
40 #include <ac/dirent.h>
41
42 #include "ldap-int.h"
43 #include "ldap-tls.h"
44
45 #define READ_PASSWORD_FROM_STDIN
46 #define READ_PASSWORD_FROM_FILE
47
48 #ifdef READ_PASSWORD_FROM_STDIN
49 #include <termios.h> /* for echo on/off */
50 #endif
51
52 #include <nspr/nspr.h>
53 #include <nspr/private/pprio.h>
54 #include <nss/nss.h>
55 #include <nss/ssl.h>
56 #include <nss/sslerr.h>
57 #include <nss/sslproto.h>
58 #include <nss/pk11pub.h>
59 #include <nss/secerr.h>
60 #include <nss/keyhi.h>
61 #include <nss/secmod.h>
62 #include <nss/cert.h>
63
64 #undef NSS_VERSION_INT
65 #define NSS_VERSION_INT ((NSS_VMAJOR << 24) | (NSS_VMINOR << 16) | \
66         (NSS_VPATCH << 8) | NSS_VBUILD)
67
68 /* NSS 3.12.5 and later have NSS_InitContext */
69 #if NSS_VERSION_INT >= 0x030c0500
70 #define HAVE_NSS_INITCONTEXT 1
71 #endif
72
73 /* NSS 3.12.9 and later have SECMOD_RestartModules */
74 #if NSS_VERSION_INT >= 0x030c0900
75 #define HAVE_SECMOD_RESTARTMODULES 1
76 #endif
77
78 /* InitContext does not currently work in server mode */
79 /* #define INITCONTEXT_HACK 1 */
80
81 typedef struct tlsm_ctx {
82         PRFileDesc *tc_model;
83         int tc_refcnt;
84         int tc_unique; /* unique number associated with this ctx */
85         PRBool tc_verify_cert;
86         CERTCertDBHandle *tc_certdb;
87         PK11SlotInfo *tc_certdb_slot;
88         CERTCertificate *tc_certificate;
89         SECKEYPrivateKey *tc_private_key;
90         char *tc_pin_file;
91         struct ldaptls *tc_config;
92         int tc_is_server;
93         int tc_require_cert;
94         PRCallOnceType tc_callonce;
95         PRBool tc_using_pem;
96 #ifdef HAVE_NSS_INITCONTEXT
97         NSSInitContext *tc_initctx; /* the NSS context */
98 #endif
99         PK11GenericObject **tc_pem_objs; /* array of objects to free */
100         int tc_n_pem_objs; /* number of objects */
101         PRBool tc_warn_only; /* only warn of errors in validation */
102 #ifdef LDAP_R_COMPILE
103         ldap_pvt_thread_mutex_t tc_refmutex;
104 #endif
105 } tlsm_ctx;
106
107 typedef PRFileDesc tlsm_session;
108
109 static int tlsm_ctx_count;
110 #define TLSM_CERTDB_DESC_FMT "ldap(%d)"
111
112 static PRDescIdentity   tlsm_layer_id;
113
114 static const PRIOMethods tlsm_PR_methods;
115
116 #define CERTDB_NONE NULL
117 #define PREFIX_NONE NULL
118
119 #define PEM_LIBRARY     "nsspem"
120 #define PEM_MODULE      "PEM"
121 /* hash files for use with cacertdir have this file name suffix */
122 #define PEM_CA_HASH_FILE_SUFFIX ".0"
123 #define PEM_CA_HASH_FILE_SUFFIX_LEN 2
124
125 static SECMODModule *pem_module;
126
127 #define DEFAULT_TOKEN_NAME "default"
128 #define TLSM_PEM_SLOT_CACERTS "PEM Token #0"
129 #define TLSM_PEM_SLOT_CERTS "PEM Token #1"
130
131 #define PK11_SETATTRS(x,id,v,l) (x).type = (id); \
132                 (x).pValue=(v); (x).ulValueLen = (l);
133
134 /* forward declaration */
135 static int tlsm_init( void );
136
137 #ifdef LDAP_R_COMPILE
138
139 /* it doesn't seem guaranteed that a client will call
140    tlsm_thr_init in a non-threaded context - so we have
141    to wrap the mutex creation in a prcallonce
142 */
143 static ldap_pvt_thread_mutex_t tlsm_ctx_count_mutex;
144 static ldap_pvt_thread_mutex_t tlsm_init_mutex;
145 static ldap_pvt_thread_mutex_t tlsm_pem_mutex;
146 static PRCallOnceType tlsm_init_mutex_callonce = {0,0};
147
148 static PRStatus PR_CALLBACK
149 tlsm_thr_init_callonce( void )
150 {
151         if ( ldap_pvt_thread_mutex_init( &tlsm_ctx_count_mutex ) ) {
152                 Debug( LDAP_DEBUG_ANY,
153                            "TLS: could not create mutex for context counter: %d\n", errno, 0, 0 );
154                 return PR_FAILURE;
155         }
156
157         if ( ldap_pvt_thread_mutex_init( &tlsm_init_mutex ) ) {
158                 Debug( LDAP_DEBUG_ANY,
159                            "TLS: could not create mutex for moznss initialization: %d\n", errno, 0, 0 );
160                 return PR_FAILURE;
161         }
162
163         if ( ldap_pvt_thread_mutex_init( &tlsm_pem_mutex ) ) {
164                 Debug( LDAP_DEBUG_ANY,
165                            "TLS: could not create mutex for PEM module: %d\n", errno, 0, 0 );
166                 return PR_FAILURE;
167         }
168
169         return PR_SUCCESS;
170 }
171
172 static void
173 tlsm_thr_init( void )
174 {
175     ( void )PR_CallOnce( &tlsm_init_mutex_callonce, tlsm_thr_init_callonce );
176 }
177
178 #endif /* LDAP_R_COMPILE */
179
180 static const char *
181 tlsm_dump_cipher_info(PRFileDesc *fd)
182 {
183         PRUint16 ii;
184
185         for (ii = 0; ii < SSL_NumImplementedCiphers; ++ii) {
186                 PRInt32 cipher = (PRInt32)SSL_ImplementedCiphers[ii];
187                 PRBool enabled = PR_FALSE;
188                 PRInt32 policy = 0;
189                 SSLCipherSuiteInfo info;
190
191                 if (fd) {
192                         SSL_CipherPrefGet(fd, cipher, &enabled);
193                 } else {
194                         SSL_CipherPrefGetDefault(cipher, &enabled);
195                 }
196                 SSL_CipherPolicyGet(cipher, &policy);
197                 SSL_GetCipherSuiteInfo(cipher, &info, (PRUintn)sizeof(info));
198                 Debug( LDAP_DEBUG_TRACE,
199                            "TLS: cipher: %d - %s, enabled: %d, ",
200                            info.cipherSuite, info.cipherSuiteName, enabled );
201                 Debug( LDAP_DEBUG_TRACE,
202                            "policy: %d\n", policy, 0, 0 );
203         }
204
205         return "";
206 }
207
208 /* Cipher definitions */
209 typedef struct {
210         char *ossl_name;    /* The OpenSSL cipher name */
211         int num;            /* The cipher id */
212         int attr;           /* cipher attributes: algorithms, etc */
213         int version;        /* protocol version valid for this cipher */
214         int bits;           /* bits of strength */
215         int alg_bits;       /* bits of the algorithm */
216         int strength;       /* LOW, MEDIUM, HIGH */
217         int enabled;        /* Enabled by default? */
218 } cipher_properties;
219
220 /* cipher attributes  */
221 #define SSL_kRSA  0x00000001L
222 #define SSL_aRSA  0x00000002L
223 #define SSL_aDSS  0x00000004L
224 #define SSL_DSS   SSL_aDSS
225 #define SSL_eNULL 0x00000008L
226 #define SSL_DES   0x00000010L
227 #define SSL_3DES  0x00000020L
228 #define SSL_RC4   0x00000040L
229 #define SSL_RC2   0x00000080L
230 #define SSL_AES   0x00000100L
231 #define SSL_MD5   0x00000200L
232 #define SSL_SHA1  0x00000400L
233 #define SSL_SHA   SSL_SHA1
234 #define SSL_RSA   (SSL_kRSA|SSL_aRSA)
235
236 /* cipher strength */
237 #define SSL_NULL      0x00000001L
238 #define SSL_EXPORT40  0x00000002L
239 #define SSL_EXPORT56  0x00000004L
240 #define SSL_LOW       0x00000008L
241 #define SSL_MEDIUM    0x00000010L
242 #define SSL_HIGH      0x00000020L
243
244 #define SSL2  0x00000001L
245 #define SSL3  0x00000002L
246 /* OpenSSL treats SSL3 and TLSv1 the same */
247 #define TLS1  SSL3
248
249 /* Cipher translation */
250 static cipher_properties ciphers_def[] = {
251         /* SSL 2 ciphers */
252         {"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},
253         {"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},
254         {"RC4-MD5", SSL_EN_RC4_128_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL2, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
255         {"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},
256         {"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},
257         {"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},
258
259         /* SSL3 ciphers */
260         {"RC4-MD5", SSL_RSA_WITH_RC4_128_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL3, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
261         {"RC4-SHA", SSL_RSA_WITH_RC4_128_SHA, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA1, SSL3, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
262         {"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},
263         {"DES-CBC-SHA", SSL_RSA_WITH_DES_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, SSL3, 56, 56, SSL_LOW, SSL_ALLOWED},
264         {"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},
265         {"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},
266         {"NULL-MD5", SSL_RSA_WITH_NULL_MD5, SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_MD5, SSL3, 0, 0, SSL_NULL, SSL_NOT_ALLOWED},
267         {"NULL-SHA", SSL_RSA_WITH_NULL_SHA, SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_SHA1, SSL3, 0, 0, SSL_NULL, SSL_NOT_ALLOWED},
268
269         /* TLSv1 ciphers */
270         {"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},
271         {"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},
272         {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA, TLS1, 128, 128, SSL_HIGH, SSL_ALLOWED},
273         {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA, TLS1, 256, 256, SSL_HIGH, SSL_ALLOWED},
274 };
275
276 #define ciphernum (sizeof(ciphers_def)/sizeof(cipher_properties))
277
278 /* given err which is the current errno, calls PR_SetError with
279    the corresponding NSPR error code */
280 static void 
281 tlsm_map_error(int err)
282 {
283         PRErrorCode prError;
284
285         switch ( err ) {
286         case EACCES:
287                 prError = PR_NO_ACCESS_RIGHTS_ERROR;
288                 break;
289         case EADDRINUSE:
290                 prError = PR_ADDRESS_IN_USE_ERROR;
291                 break;
292         case EADDRNOTAVAIL:
293                 prError = PR_ADDRESS_NOT_AVAILABLE_ERROR;
294                 break;
295         case EAFNOSUPPORT:
296                 prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
297                 break;
298         case EAGAIN:
299                 prError = PR_WOULD_BLOCK_ERROR;
300                 break;
301         /*
302          * On QNX and Neutrino, EALREADY is defined as EBUSY.
303          */
304 #if EALREADY != EBUSY
305         case EALREADY:
306                 prError = PR_ALREADY_INITIATED_ERROR;
307                 break;
308 #endif
309         case EBADF:
310                 prError = PR_BAD_DESCRIPTOR_ERROR;
311                 break;
312 #ifdef EBADMSG
313         case EBADMSG:
314                 prError = PR_IO_ERROR;
315                 break;
316 #endif
317         case EBUSY:
318                 prError = PR_FILESYSTEM_MOUNTED_ERROR;
319                 break;
320         case ECONNABORTED:
321                 prError = PR_CONNECT_ABORTED_ERROR;
322                 break;
323         case ECONNREFUSED:
324                 prError = PR_CONNECT_REFUSED_ERROR;
325                 break;
326         case ECONNRESET:
327                 prError = PR_CONNECT_RESET_ERROR;
328                 break;
329         case EDEADLK:
330                 prError = PR_DEADLOCK_ERROR;
331                 break;
332 #ifdef EDIRCORRUPTED
333         case EDIRCORRUPTED:
334                 prError = PR_DIRECTORY_CORRUPTED_ERROR;
335                 break;
336 #endif
337 #ifdef EDQUOT
338         case EDQUOT:
339                 prError = PR_NO_DEVICE_SPACE_ERROR;
340                 break;
341 #endif
342         case EEXIST:
343                 prError = PR_FILE_EXISTS_ERROR;
344                 break;
345         case EFAULT:
346                 prError = PR_ACCESS_FAULT_ERROR;
347                 break;
348         case EFBIG:
349                 prError = PR_FILE_TOO_BIG_ERROR;
350                 break;
351         case EHOSTUNREACH:
352                 prError = PR_HOST_UNREACHABLE_ERROR;
353                 break;
354         case EINPROGRESS:
355                 prError = PR_IN_PROGRESS_ERROR;
356                 break;
357         case EINTR:
358                 prError = PR_PENDING_INTERRUPT_ERROR;
359                 break;
360         case EINVAL:
361                 prError = PR_INVALID_ARGUMENT_ERROR;
362                 break;
363         case EIO:
364                 prError = PR_IO_ERROR;
365                 break;
366         case EISCONN:
367                 prError = PR_IS_CONNECTED_ERROR;
368                 break;
369         case EISDIR:
370                 prError = PR_IS_DIRECTORY_ERROR;
371                 break;
372         case ELOOP:
373                 prError = PR_LOOP_ERROR;
374                 break;
375         case EMFILE:
376                 prError = PR_PROC_DESC_TABLE_FULL_ERROR;
377                 break;
378         case EMLINK:
379                 prError = PR_MAX_DIRECTORY_ENTRIES_ERROR;
380                 break;
381         case EMSGSIZE:
382                 prError = PR_INVALID_ARGUMENT_ERROR;
383                 break;
384 #ifdef EMULTIHOP
385         case EMULTIHOP:
386                 prError = PR_REMOTE_FILE_ERROR;
387                 break;
388 #endif
389         case ENAMETOOLONG:
390                 prError = PR_NAME_TOO_LONG_ERROR;
391                 break;
392         case ENETUNREACH:
393                 prError = PR_NETWORK_UNREACHABLE_ERROR;
394                 break;
395         case ENFILE:
396                 prError = PR_SYS_DESC_TABLE_FULL_ERROR;
397                 break;
398         /*
399          * On SCO OpenServer 5, ENOBUFS is defined as ENOSR.
400          */
401 #if defined(ENOBUFS) && (ENOBUFS != ENOSR)
402         case ENOBUFS:
403                 prError = PR_INSUFFICIENT_RESOURCES_ERROR;
404                 break;
405 #endif
406         case ENODEV:
407                 prError = PR_FILE_NOT_FOUND_ERROR;
408                 break;
409         case ENOENT:
410                 prError = PR_FILE_NOT_FOUND_ERROR;
411                 break;
412         case ENOLCK:
413                 prError = PR_FILE_IS_LOCKED_ERROR;
414                 break;
415 #ifdef ENOLINK 
416         case ENOLINK:
417                 prError = PR_REMOTE_FILE_ERROR;
418                 break;
419 #endif
420         case ENOMEM:
421                 prError = PR_OUT_OF_MEMORY_ERROR;
422                 break;
423         case ENOPROTOOPT:
424                 prError = PR_INVALID_ARGUMENT_ERROR;
425                 break;
426         case ENOSPC:
427                 prError = PR_NO_DEVICE_SPACE_ERROR;
428                 break;
429 #ifdef ENOSR
430         case ENOSR:
431                 prError = PR_INSUFFICIENT_RESOURCES_ERROR;
432                 break;
433 #endif
434         case ENOTCONN:
435                 prError = PR_NOT_CONNECTED_ERROR;
436                 break;
437         case ENOTDIR:
438                 prError = PR_NOT_DIRECTORY_ERROR;
439                 break;
440         case ENOTSOCK:
441                 prError = PR_NOT_SOCKET_ERROR;
442                 break;
443         case ENXIO:
444                 prError = PR_FILE_NOT_FOUND_ERROR;
445                 break;
446         case EOPNOTSUPP:
447                 prError = PR_NOT_TCP_SOCKET_ERROR;
448                 break;
449 #ifdef EOVERFLOW
450         case EOVERFLOW:
451                 prError = PR_BUFFER_OVERFLOW_ERROR;
452                 break;
453 #endif
454         case EPERM:
455                 prError = PR_NO_ACCESS_RIGHTS_ERROR;
456                 break;
457         case EPIPE:
458                 prError = PR_CONNECT_RESET_ERROR;
459                 break;
460 #ifdef EPROTO
461         case EPROTO:
462                 prError = PR_IO_ERROR;
463                 break;
464 #endif
465         case EPROTONOSUPPORT:
466                 prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR;
467                 break;
468         case EPROTOTYPE:
469                 prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
470                 break;
471         case ERANGE:
472                 prError = PR_INVALID_METHOD_ERROR;
473                 break;
474         case EROFS:
475                 prError = PR_READ_ONLY_FILESYSTEM_ERROR;
476                 break;
477         case ESPIPE:
478                 prError = PR_INVALID_METHOD_ERROR;
479                 break;
480         case ETIMEDOUT:
481                 prError = PR_IO_TIMEOUT_ERROR;
482                 break;
483 #if EWOULDBLOCK != EAGAIN
484         case EWOULDBLOCK:
485                 prError = PR_WOULD_BLOCK_ERROR;
486                 break;
487 #endif
488         case EXDEV:
489                 prError = PR_NOT_SAME_DEVICE_ERROR;
490                 break;
491         default:
492                 prError = PR_UNKNOWN_ERROR;
493                 break;
494         }
495         PR_SetError( prError, err );
496 }
497
498 /*
499  * cipher_list is an integer array with the following values:
500  *   -1: never enable this cipher
501  *    0: cipher disabled
502  *    1: cipher enabled
503  */
504 static int
505 nss_parse_ciphers(const char *cipherstr, int cipher_list[ciphernum])
506 {
507         int i;
508         char *cipher;
509         char *ciphers;
510         char *ciphertip;
511         int action;
512         int rv;
513
514         /* All disabled to start */
515         for (i=0; i<ciphernum; i++)
516                 cipher_list[i] = 0;
517
518         ciphertip = strdup(cipherstr);
519         cipher = ciphers = ciphertip;
520
521         while (ciphers && (strlen(ciphers))) {
522                 while ((*cipher) && (isspace(*cipher)))
523                         ++cipher;
524
525                 action = 1;
526                 switch(*cipher) {
527                 case '+': /* Add something */
528                         action = 1;
529                         cipher++;
530                         break;
531                 case '-': /* Subtract something */
532                         action = 0;
533                         cipher++;
534                         break;
535                 case '!':  /* Disable something */
536                         action = -1;
537                         cipher++;
538                         break;
539                 default:
540                         /* do nothing */
541                         break;
542                 }
543
544                 if ((ciphers = strchr(cipher, ':'))) {
545                         *ciphers++ = '\0';
546                 }
547
548                 /* Do the easy one first */
549                 if (!strcmp(cipher, "ALL")) {
550                         for (i=0; i<ciphernum; i++) {
551                                 if (!(ciphers_def[i].attr & SSL_eNULL))
552                                         cipher_list[i] = action;
553                         }
554                 } else if (!strcmp(cipher, "COMPLEMENTOFALL")) {
555                         for (i=0; i<ciphernum; i++) {
556                                 if ((ciphers_def[i].attr & SSL_eNULL))
557                                         cipher_list[i] = action;
558                         }
559                 } else if (!strcmp(cipher, "DEFAULT")) {
560                         for (i=0; i<ciphernum; i++) {
561                                 cipher_list[i] = ciphers_def[i].enabled == SSL_ALLOWED ? 1 : 0;
562                         }
563                 } else {
564                         int mask = 0;
565                         int strength = 0;
566                         int protocol = 0;
567                         char *c;
568
569                         c = cipher;
570                         while (c && (strlen(c))) {
571
572                                 if ((c = strchr(cipher, '+'))) {
573                                         *c++ = '\0';
574                                 }
575
576                                 if (!strcmp(cipher, "RSA")) {
577                                         mask |= SSL_RSA;
578                                 } else if ((!strcmp(cipher, "NULL")) || (!strcmp(cipher, "eNULL"))) {
579                                         mask |= SSL_eNULL;
580                                 } else if (!strcmp(cipher, "AES")) {
581                                         mask |= SSL_AES;
582                                 } else if (!strcmp(cipher, "3DES")) {
583                                         mask |= SSL_3DES;
584                                 } else if (!strcmp(cipher, "DES")) {
585                                         mask |= SSL_DES;
586                                 } else if (!strcmp(cipher, "RC4")) {
587                                         mask |= SSL_RC4;
588                                 } else if (!strcmp(cipher, "RC2")) {
589                                         mask |= SSL_RC2;
590                                 } else if (!strcmp(cipher, "MD5")) {
591                                         mask |= SSL_MD5;
592                                 } else if ((!strcmp(cipher, "SHA")) || (!strcmp(cipher, "SHA1"))) {
593                                         mask |= SSL_SHA1;
594                                 } else if (!strcmp(cipher, "SSLv2")) {
595                                         protocol |= SSL2;
596                                 } else if (!strcmp(cipher, "SSLv3")) {
597                                         protocol |= SSL3;
598                                 } else if (!strcmp(cipher, "TLSv1")) {
599                                         protocol |= TLS1;
600                                 } else if (!strcmp(cipher, "HIGH")) {
601                                         strength |= SSL_HIGH;
602                                 } else if (!strcmp(cipher, "MEDIUM")) {
603                                         strength |= SSL_MEDIUM;
604                                 } else if (!strcmp(cipher, "LOW")) {
605                                         strength |= SSL_LOW;
606                                 } else if ((!strcmp(cipher, "EXPORT")) || (!strcmp(cipher, "EXP"))) {
607                                         strength |= SSL_EXPORT40|SSL_EXPORT56;
608                                 } else if (!strcmp(cipher, "EXPORT40")) {
609                                         strength |= SSL_EXPORT40;
610                                 } else if (!strcmp(cipher, "EXPORT56")) {
611                                         strength |= SSL_EXPORT56;
612                                 }
613
614                                 if (c)
615                                         cipher = c;
616
617                         } /* while */
618
619                         /* If we have a mask, apply it. If not then perhaps they provided
620                          * a specific cipher to enable.
621                          */
622                         if (mask || strength || protocol) {
623                                 for (i=0; i<ciphernum; i++) {
624                                         if (((ciphers_def[i].attr & mask) ||
625                                                  (ciphers_def[i].strength & strength) ||
626                                                  (ciphers_def[i].version & protocol)) &&
627                                                 (cipher_list[i] != -1)) {
628                                                 /* Enable the NULL ciphers only if explicity
629                                                  * requested */
630                                                 if (ciphers_def[i].attr & SSL_eNULL) {
631                                                         if (mask & SSL_eNULL)
632                                                                 cipher_list[i] = action;
633                                                 } else
634                                                         cipher_list[i] = action;
635                                         }
636                                 }
637                         } else {
638                                 for (i=0; i<ciphernum; i++) {
639                                         if (!strcmp(ciphers_def[i].ossl_name, cipher) &&
640                                                 cipher_list[i] != -1)
641                                                 cipher_list[i] = action;
642                                 }
643                         }
644                 }
645
646                 if (ciphers)
647                         cipher = ciphers;
648         }
649
650         /* See if any ciphers were enabled */
651         rv = 0;
652         for (i=0; i<ciphernum; i++) {
653                 if (cipher_list[i] == 1)
654                         rv = 1;
655         }
656
657         free(ciphertip);
658
659         return rv;
660 }
661
662 static int
663 tlsm_parse_ciphers(tlsm_ctx *ctx, const char *str)
664 {
665         int cipher_state[ciphernum];
666         int rv, i;
667
668         if (!ctx)
669                 return 0;
670
671         rv = nss_parse_ciphers(str, cipher_state);
672
673         if (rv) {
674                 /* First disable everything */
675                 for (i = 0; i < SSL_NumImplementedCiphers; i++)
676                         SSL_CipherPrefSet(ctx->tc_model, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED);
677
678                 /* Now enable what was requested */
679                 for (i=0; i<ciphernum; i++) {
680                         SSLCipherSuiteInfo suite;
681                         PRBool enabled;
682
683                         if (SSL_GetCipherSuiteInfo(ciphers_def[i].num, &suite, sizeof suite)
684                                 == SECSuccess) {
685                                 enabled = cipher_state[i] < 0 ? 0 : cipher_state[i];
686                                 if (enabled == SSL_ALLOWED) {
687                                         if (PK11_IsFIPS() && !suite.isFIPS)    
688                                                 enabled = SSL_NOT_ALLOWED;
689                                 }
690                                 SSL_CipherPrefSet(ctx->tc_model, ciphers_def[i].num, enabled);
691                         }
692                 }
693         }
694
695         return rv == 1 ? 0 : -1;
696 }
697
698 static SECStatus
699 tlsm_bad_cert_handler(void *arg, PRFileDesc *ssl)
700 {
701         SECStatus success = SECSuccess;
702         PRErrorCode err;
703         tlsm_ctx *ctx = (tlsm_ctx *)arg;
704
705         if (!ssl || !ctx) {
706                 return SECFailure;
707         }
708
709         err = PORT_GetError();
710
711         switch (err) {
712         case SEC_ERROR_UNTRUSTED_ISSUER:
713         case SEC_ERROR_UNKNOWN_ISSUER:
714         case SEC_ERROR_EXPIRED_CERTIFICATE:
715         case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
716                 if (ctx->tc_verify_cert) {
717                         success = SECFailure;
718                 }
719                 break;
720         /* we bypass NSS's hostname checks and do our own */
721         case SSL_ERROR_BAD_CERT_DOMAIN:
722                 break;
723         default:
724                 success = SECFailure;
725                 break;
726         }
727
728         return success;
729 }
730
731 static const char *
732 tlsm_dump_security_status(PRFileDesc *fd)
733 {
734         char * cp;      /* bulk cipher name */
735         char * ip;      /* cert issuer DN */
736         char * sp;      /* cert subject DN */
737         int    op;      /* High, Low, Off */
738         int    kp0;     /* total key bits */
739         int    kp1;     /* secret key bits */
740         SSL3Statistics * ssl3stats = SSL_GetStatistics();
741
742         SSL_SecurityStatus( fd, &op, &cp, &kp0, &kp1, &ip, &sp );
743         Debug( LDAP_DEBUG_TRACE,
744                    "TLS certificate verification: subject: %s, issuer: %s, cipher: %s, ",
745                    sp ? sp : "-unknown-", ip ? ip : "-unknown-", cp ? cp : "-unknown-" );
746         PR_Free(cp);
747         PR_Free(ip);
748         PR_Free(sp);
749         Debug( LDAP_DEBUG_TRACE,
750                    "security level: %s, secret key bits: %d, total key bits: %d, ",
751                    ((op == SSL_SECURITY_STATUS_ON_HIGH) ? "high" :
752                         ((op == SSL_SECURITY_STATUS_ON_LOW) ? "low" : "off")),
753                    kp1, kp0 );
754
755         Debug( LDAP_DEBUG_TRACE,
756                    "cache hits: %ld, cache misses: %ld, cache not reusable: %ld\n",
757                    ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
758                    ssl3stats->hch_sid_cache_not_ok );
759
760         return "";
761 }
762
763 static void
764 tlsm_handshake_complete_cb( PRFileDesc *fd, void *client_data )
765 {
766         tlsm_dump_security_status( fd );
767 }
768
769 #ifdef READ_PASSWORD_FROM_FILE
770 static char *
771 tlsm_get_pin_from_file(const char *token_name, tlsm_ctx *ctx)
772 {
773         char *pwdstr = NULL;
774         char *contents = NULL;
775         char *lasts = NULL;
776         char *line = NULL;
777         char *candidate = NULL;
778         PRFileInfo file_info;
779         PRFileDesc *pwd_fileptr = PR_Open( ctx->tc_pin_file, PR_RDONLY, 00400 );
780
781         /* open the password file */
782         if ( !pwd_fileptr ) {
783                 PRErrorCode errcode = PR_GetError();
784                 Debug( LDAP_DEBUG_ANY,
785                        "TLS: could not open security pin file %s - error %d:%s.\n",
786                        ctx->tc_pin_file, errcode,
787                        PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
788                 goto done;
789         }
790
791         /* get the file size */
792         if ( PR_SUCCESS != PR_GetFileInfo( ctx->tc_pin_file, &file_info ) ) {
793                 PRErrorCode errcode = PR_GetError();
794                 Debug( LDAP_DEBUG_ANY,
795                        "TLS: could not get file info from pin file %s - error %d:%s.\n",
796                        ctx->tc_pin_file, errcode,
797                        PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
798                 goto done;
799         }
800
801         /* create a buffer to hold the file contents */
802         if ( !( contents = PR_CALLOC( file_info.size + 1 ) ) ) {
803                 PRErrorCode errcode = PR_GetError();
804                 Debug( LDAP_DEBUG_ANY,
805                        "TLS: could not alloc a buffer for contents of pin file %s - error %d:%s.\n",
806                        ctx->tc_pin_file, errcode,
807                        PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
808                 goto done;
809         }
810
811         /* read file into the buffer */
812         if( PR_Read( pwd_fileptr, contents, file_info.size ) <= 0 ) {
813                 PRErrorCode errcode = PR_GetError();
814                 Debug( LDAP_DEBUG_ANY,
815                        "TLS: could not read the file contents from pin file %s - error %d:%s.\n",
816                        ctx->tc_pin_file, errcode,
817                        PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
818                 goto done;
819         }
820
821         /* format is [tokenname:]password EOL [tokenname:]password EOL ... */
822         /* if you want to use a password containing a colon character, use
823            the special tokenname "default" */
824         for ( line = PL_strtok_r( contents, "\r\n", &lasts ); line;
825               line = PL_strtok_r( NULL, "\r\n", &lasts ) ) {
826                 char *colon;
827
828                 if ( !*line ) {
829                         continue; /* skip blank lines */
830                 }
831                 colon = PL_strchr( line, ':' );
832                 if ( colon ) {
833                         if ( *(colon + 1) && token_name &&
834                              !PL_strncmp( token_name, line, colon-line ) ) {
835                                 candidate = colon + 1; /* found a definite match */
836                                 break;
837                         } else if ( !PL_strncmp( DEFAULT_TOKEN_NAME, line, colon-line ) ) {
838                                 candidate = colon + 1; /* found possible match */
839                         }
840                 } else { /* no token name */
841                         candidate = line;
842                 }
843         }
844 done:
845         if ( pwd_fileptr ) {
846                 PR_Close( pwd_fileptr );
847         }
848         if ( candidate ) {
849                 pwdstr = PL_strdup( candidate );
850         }
851         PL_strfree( contents );
852
853         return pwdstr;
854 }
855 #endif /* READ_PASSWORD_FROM_FILE */
856
857 #ifdef READ_PASSWORD_FROM_STDIN
858 /*
859  * Turn the echoing off on a tty.
860  */
861 static void
862 echoOff(int fd)
863 {
864         if ( isatty( fd ) ) {
865                 struct termios tio;
866                 tcgetattr( fd, &tio );
867                 tio.c_lflag &= ~ECHO;
868                 tcsetattr( fd, TCSAFLUSH, &tio );
869         }
870 }
871
872 /*
873  * Turn the echoing on on a tty.
874  */
875 static void
876 echoOn(int fd)
877 {
878         if ( isatty( fd ) ) {
879                 struct termios tio;
880                 tcgetattr( fd, &tio );
881                 tio.c_lflag |= ECHO;
882                 tcsetattr( fd, TCSAFLUSH, &tio );
883                 tcsetattr( fd, TCSAFLUSH, &tio );
884         }
885 }
886 #endif /* READ_PASSWORD_FROM_STDIN */
887
888 /*
889  * This does the actual work of reading the pin/password/pass phrase
890  */
891 static char *
892 tlsm_get_pin(PK11SlotInfo *slot, PRBool retry, tlsm_ctx *ctx)
893 {
894         char *token_name = NULL;
895         char *pwdstr = NULL;
896
897         token_name = PK11_GetTokenName( slot );
898 #ifdef READ_PASSWORD_FROM_FILE
899         /* Try to get the passwords from the password file if it exists.
900          * THIS IS UNSAFE and is provided for convenience only. Without this
901          * capability the server would have to be started in foreground mode
902          * if using an encrypted key.
903          */
904         if ( ctx->tc_pin_file ) {
905                 pwdstr = tlsm_get_pin_from_file( token_name, ctx );
906                 if (retry && pwdstr != NULL)
907                         return NULL;
908         }
909 #endif /* RETRIEVE_PASSWORD_FROM_FILE */
910 #ifdef READ_PASSWORD_FROM_STDIN
911         if ( !pwdstr ) {
912                 int infd = PR_FileDesc2NativeHandle( PR_STDIN );
913                 int isTTY = isatty( infd );
914                 unsigned char phrase[200];
915                 /* Prompt for password */
916                 if ( isTTY ) {
917                         fprintf( stdout,
918                                  "Please enter pin, password, or pass phrase for security token '%s': ",
919                                  token_name ? token_name : DEFAULT_TOKEN_NAME );
920                         echoOff( infd );
921                 }
922                 fgets( (char*)phrase, sizeof(phrase), stdin );
923                 if ( isTTY ) {
924                         fprintf( stdout, "\n" );
925                         echoOn( infd );
926                 }
927                 /* stomp on newline */
928                 phrase[strlen((char*)phrase)-1] = 0;
929
930                 pwdstr = PL_strdup( (char*)phrase );
931         }
932
933 #endif /* READ_PASSWORD_FROM_STDIN */
934         return pwdstr;
935 }
936
937 /*
938  * PKCS11 devices (including the internal softokn cert/key database)
939  * may be protected by a pin or password or even pass phrase
940  * MozNSS needs a way for the user to provide that
941  */
942 static char *
943 tlsm_pin_prompt(PK11SlotInfo *slot, PRBool retry, void *arg)
944 {
945         tlsm_ctx *ctx = (tlsm_ctx *)arg;
946
947         return tlsm_get_pin( slot, retry, ctx );
948 }
949
950 static char *
951 tlsm_ctx_subject_name(tlsm_ctx *ctx)
952 {
953         if (!ctx || !ctx->tc_certificate)
954                 return "(unknown)";
955
956         return ctx->tc_certificate->subjectName;
957 }
958
959 static SECStatus
960 tlsm_get_basic_constraint_extension( CERTCertificate *cert,
961                                                                          CERTBasicConstraints *cbcval )
962 {
963         SECItem encodedVal = { 0, NULL };
964         SECStatus rc;
965
966         rc = CERT_FindCertExtension( cert, SEC_OID_X509_BASIC_CONSTRAINTS,
967                                                                  &encodedVal);
968         if ( rc != SECSuccess ) {
969                 return rc;
970         }
971
972         rc = CERT_DecodeBasicConstraintValue( cbcval, &encodedVal );
973
974         /* free the raw extension data */
975         PORT_Free( encodedVal.data );
976
977         return rc;
978 }
979
980 static PRBool
981 tlsm_cert_is_self_issued( CERTCertificate *cert )
982 {
983         /* A cert is self-issued if its subject and issuer are equal and
984          * both are of non-zero length. 
985          */
986         PRBool is_self_issued = cert &&
987                 (PRBool)SECITEM_ItemsAreEqual( &cert->derIssuer, 
988                                                                            &cert->derSubject ) &&
989                 cert->derSubject.len > 0;
990         return is_self_issued;
991 }
992
993 static SECStatus
994 tlsm_verify_cert(CERTCertDBHandle *handle, CERTCertificate *cert, void *pinarg,
995                                  PRBool checksig, SECCertificateUsage certUsage, int errorToIgnore )
996 {
997         CERTVerifyLog verifylog;
998         SECStatus ret = SECSuccess;
999         const char *name;
1000         int debug_level = LDAP_DEBUG_ANY;
1001
1002         if ( errorToIgnore == -1 ) {
1003                 debug_level = LDAP_DEBUG_TRACE;
1004         }
1005
1006         /* the log captures information about every cert in the chain, so we can tell
1007            which cert caused the problem and what the problem was */
1008         memset( &verifylog, 0, sizeof( verifylog ) );
1009         verifylog.arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
1010         if ( verifylog.arena == NULL ) {
1011                 Debug( LDAP_DEBUG_ANY,
1012                            "TLS certificate verification: Out of memory for certificate verification logger\n",
1013                            0, 0, 0 );
1014                 return SECFailure;
1015         }
1016         ret = CERT_VerifyCertificate( handle, cert, checksig, certUsage, PR_Now(), pinarg, &verifylog,
1017                                                                   NULL );
1018         if ( ( name = cert->subjectName ) == NULL ) {
1019                 name = cert->nickname;
1020         }
1021         if ( verifylog.head == NULL ) {
1022                 /* it is possible for CERT_VerifyCertificate return with an error with no logging */
1023                 if ( ret != SECSuccess ) {
1024                         PRErrorCode errcode = PR_GetError();
1025                         Debug( debug_level,
1026                                    "TLS: certificate [%s] is not valid - error %d:%s.\n",
1027                                    name ? name : "(unknown)",
1028                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1029                 }
1030         } else {
1031                 const char *name;
1032                 CERTVerifyLogNode *node;
1033
1034                 ret = SECSuccess; /* reset */
1035                 node = verifylog.head;
1036                 while ( node ) {
1037                         if ( ( name = node->cert->subjectName ) == NULL ) {
1038                                 name = node->cert->nickname;
1039                         }
1040                         if ( node->error ) {
1041                                 /* NSS does not like CA certs that have the basic constraints extension
1042                                    with the CA flag set to FALSE - openssl doesn't check if the cert
1043                                    is self issued */
1044                                 if ( ( node->error == SEC_ERROR_CA_CERT_INVALID ) &&
1045                                          tlsm_cert_is_self_issued( node->cert ) ) {
1046
1047                                         PRErrorCode orig_error = PR_GetError();
1048                                         PRInt32 orig_oserror = PR_GetOSError();
1049
1050                                         CERTBasicConstraints basicConstraint;
1051                                         SECStatus rv = tlsm_get_basic_constraint_extension( node->cert, &basicConstraint );
1052                                         if ( ( rv == SECSuccess ) && ( basicConstraint.isCA == PR_FALSE ) ) {
1053                                                 Debug( LDAP_DEBUG_TRACE,
1054                                                            "TLS: certificate [%s] is not correct because it is a CA cert and the "
1055                                                            "BasicConstraint CA flag is set to FALSE - allowing for now, but "
1056                                                            "please fix your certs if possible\n", name, 0, 0 );
1057                                         } else { /* does not have basicconstraint, or some other error */
1058                                                 ret = SECFailure;
1059                                                 Debug( debug_level,
1060                                                            "TLS: certificate [%s] is not valid - CA cert is not valid\n",
1061                                                            name, 0, 0 );
1062                                         }
1063
1064                                         PR_SetError(orig_error, orig_oserror);
1065
1066                                 } else if ( errorToIgnore && ( node->error == errorToIgnore ) ) {
1067                                         Debug( debug_level,
1068                                                    "TLS: Warning: ignoring error for certificate [%s] - error %ld:%s.\n",
1069                                                    name, node->error, PR_ErrorToString( node->error, PR_LANGUAGE_I_DEFAULT ) );
1070                                 } else {
1071                                         ret = SECFailure;
1072                                         Debug( debug_level,
1073                                                    "TLS: certificate [%s] is not valid - error %ld:%s.\n",
1074                                                    name, node->error, PR_ErrorToString( node->error, PR_LANGUAGE_I_DEFAULT ) );
1075                                 }
1076                         }
1077                         CERT_DestroyCertificate( node->cert );
1078                         node = node->next;
1079                 }
1080         }
1081
1082         PORT_FreeArena( verifylog.arena, PR_FALSE );
1083
1084         if ( ret == SECSuccess ) {
1085                 Debug( LDAP_DEBUG_TRACE,
1086                            "TLS: certificate [%s] is valid\n", name, 0, 0 );
1087         } else if ( errorToIgnore == -1 ) {
1088                 ret = SECSuccess;
1089         }
1090
1091         return ret;
1092 }
1093
1094 static SECStatus
1095 tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
1096                        PRBool checksig, PRBool isServer)
1097 {
1098         SECCertificateUsage certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer;
1099         SECStatus ret = SECSuccess;
1100         CERTCertificate *peercert = SSL_PeerCertificate( fd );
1101         int errorToIgnore = 0;
1102         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1103
1104         if (ctx && ctx->tc_warn_only )
1105                 errorToIgnore = -1;
1106
1107         ret = tlsm_verify_cert( ctx->tc_certdb, peercert,
1108                                                         SSL_RevealPinArg( fd ),
1109                                                         checksig, certUsage, errorToIgnore );
1110         CERT_DestroyCertificate( peercert );
1111
1112         return ret;
1113 }
1114
1115 static SECStatus
1116 tlsm_nss_shutdown_cb( void *appData, void *nssData )
1117 {
1118         SECStatus rc = SECSuccess;
1119
1120         SSL_ShutdownServerSessionIDCache();
1121
1122         if ( pem_module ) {
1123                 SECMOD_UnloadUserModule( pem_module );
1124                 SECMOD_DestroyModule( pem_module );
1125                 pem_module = NULL;
1126         }
1127         return rc;
1128 }
1129
1130 static PRCallOnceType tlsm_register_shutdown_callonce = {0,0};
1131 static PRStatus PR_CALLBACK
1132 tlsm_register_nss_shutdown_cb( void )
1133 {
1134         if ( SECSuccess == NSS_RegisterShutdown( tlsm_nss_shutdown_cb,
1135                                                                                          NULL ) ) {
1136                 return PR_SUCCESS;
1137         }
1138         return PR_FAILURE;
1139 }
1140
1141 static PRStatus
1142 tlsm_register_nss_shutdown( void )
1143 {
1144         return PR_CallOnce( &tlsm_register_shutdown_callonce,
1145                                                 tlsm_register_nss_shutdown_cb );
1146 }
1147
1148 static int
1149 tlsm_init_pem_module( void )
1150 {
1151         int rc = 0;
1152         char *fullname = NULL;
1153         char *configstring = NULL;
1154
1155         if ( pem_module ) {
1156                 return rc;
1157         }
1158
1159         /* not loaded - load it */
1160         /* get the system dependent library name */
1161         fullname = PR_GetLibraryName( NULL, PEM_LIBRARY );
1162         /* Load our PKCS#11 module */
1163         configstring = PR_smprintf( "library=%s name=" PEM_MODULE " parameters=\"\"", fullname );
1164         PL_strfree( fullname );
1165
1166         pem_module = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE );
1167         PR_smprintf_free( configstring );
1168
1169         if ( !pem_module || !pem_module->loaded ) {
1170                 if ( pem_module ) {
1171                         SECMOD_DestroyModule( pem_module );
1172                         pem_module = NULL;
1173                 }
1174                 rc = -1;
1175         }
1176
1177         return rc;
1178 }
1179
1180 static void
1181 tlsm_add_pem_obj( tlsm_ctx *ctx, PK11GenericObject *obj )
1182 {
1183         int idx = ctx->tc_n_pem_objs;
1184         ctx->tc_n_pem_objs++;
1185         ctx->tc_pem_objs = (PK11GenericObject **)
1186                 PORT_Realloc( ctx->tc_pem_objs, ctx->tc_n_pem_objs * sizeof( PK11GenericObject * ) );
1187         ctx->tc_pem_objs[idx] = obj;                                                                                                              
1188 }
1189
1190 static void
1191 tlsm_free_pem_objs( tlsm_ctx *ctx )
1192 {
1193         /* free in reverse order of allocation */
1194         while ( ctx->tc_n_pem_objs-- ) {
1195                 PK11_DestroyGenericObject( ctx->tc_pem_objs[ctx->tc_n_pem_objs] );
1196                 ctx->tc_pem_objs[ctx->tc_n_pem_objs] = NULL;
1197         }
1198         PORT_Free(ctx->tc_pem_objs);
1199         ctx->tc_pem_objs = NULL;
1200         ctx->tc_n_pem_objs = 0;
1201 }
1202
1203 static int
1204 tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca )
1205 {
1206         PK11SlotInfo *slot;
1207         PK11GenericObject *cert;
1208         CK_ATTRIBUTE attrs[4];
1209         CK_BBOOL cktrue = CK_TRUE;
1210         CK_BBOOL ckfalse = CK_FALSE;
1211         CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
1212         char *slotname;
1213         PRFileInfo fi;
1214         PRStatus status;
1215         SECItem certDER = { 0, NULL, 0 };
1216
1217         memset( &fi, 0, sizeof(fi) );
1218         status = PR_GetFileInfo( filename, &fi );
1219         if ( PR_SUCCESS != status) {
1220                 PRErrorCode errcode = PR_GetError();
1221                 Debug( LDAP_DEBUG_ANY,
1222                            "TLS: could not read certificate file %s - error %d:%s.\n",
1223                            filename, errcode,
1224                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1225                 return -1;
1226         }
1227
1228         if ( fi.type != PR_FILE_FILE ) {
1229                 PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
1230                 Debug( LDAP_DEBUG_ANY,
1231                            "TLS: error: the certificate file %s is not a file.\n",
1232                            filename, 0 ,0 );
1233                 return -1;
1234         }
1235
1236         slotname = isca ? TLSM_PEM_SLOT_CACERTS : TLSM_PEM_SLOT_CERTS;
1237         slot = PK11_FindSlotByName( slotname );
1238
1239         if ( !slot ) {
1240                 PRErrorCode errcode = PR_GetError();
1241                 Debug( LDAP_DEBUG_ANY,
1242                            "TLS: could not find the slot for the certificate '%s' - error %d:%s.\n",
1243                            filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1244                 return -1;
1245         }
1246
1247         PK11_SETATTRS( attrs[0], CKA_CLASS, &objClass, sizeof(objClass) );
1248         PK11_SETATTRS( attrs[1], CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) );
1249         PK11_SETATTRS( attrs[2], CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 );
1250         PK11_SETATTRS( attrs[3], CKA_TRUST, isca ? &cktrue : &ckfalse, sizeof(CK_BBOOL) );
1251
1252         cert = PK11_CreateGenericObject( slot, attrs, 4, PR_FALSE /* isPerm */ );
1253
1254         if ( !cert ) {
1255                 PRErrorCode errcode = PR_GetError();
1256                 Debug( LDAP_DEBUG_ANY,
1257                            "TLS: could not add the certificate '%s' - error %d:%s.\n",
1258                            filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1259                 PK11_FreeSlot( slot );
1260                 return -1;
1261         }
1262
1263         /* if not CA, we store the certificate in ctx->tc_certificate */
1264         if ( !isca ) {
1265                 if ( PK11_ReadRawAttribute( PK11_TypeGeneric, cert, CKA_VALUE, &certDER ) != SECSuccess ) {
1266                         PRErrorCode errcode = PR_GetError();
1267                         Debug( LDAP_DEBUG_ANY,
1268                                         "TLS: could not get DER of the '%s' certificate - error %d:%s.\n",
1269                                         filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1270                         PK11_DestroyGenericObject( cert );
1271                         PK11_FreeSlot( slot );
1272                         return -1;
1273                 }
1274
1275                 ctx->tc_certificate = PK11_FindCertFromDERCertItem( slot, &certDER, NULL );
1276                 SECITEM_FreeItem( &certDER, PR_FALSE );
1277
1278                 if ( !ctx->tc_certificate ) {
1279                         PRErrorCode errcode = PR_GetError();
1280                         Debug( LDAP_DEBUG_ANY,
1281                                         "TLS: could not get certificate '%s' using DER - error %d:%s.\n",
1282                                         filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1283                         PK11_DestroyGenericObject( cert );
1284                         PK11_FreeSlot( slot );
1285                         return -1;
1286                 }
1287         }
1288
1289         tlsm_add_pem_obj( ctx, cert );
1290
1291         PK11_FreeSlot( slot );
1292
1293         return 0;
1294 }
1295
1296 static int
1297 tlsm_ctx_load_private_key(tlsm_ctx *ctx)
1298 {
1299         if (!ctx->tc_certificate)
1300                 return -1;
1301
1302         if (ctx->tc_private_key)
1303                 return 0;
1304
1305         void *pin_arg = SSL_RevealPinArg(ctx->tc_model);
1306
1307         ctx->tc_private_key = PK11_FindKeyByAnyCert(ctx->tc_certificate, pin_arg);
1308         if (!ctx->tc_private_key) {
1309                 PRErrorCode errcode = PR_GetError();
1310                 Debug(LDAP_DEBUG_ANY,
1311                                 "TLS: cannot find private key for certificate '%s' (error %d: %s)",
1312                                 tlsm_ctx_subject_name(ctx), errcode,
1313                                 PR_ErrorToString(errcode, PR_LANGUAGE_I_DEFAULT));
1314                 return -1;
1315         }
1316
1317         return 0;
1318 }
1319
1320 static int
1321 tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
1322 {
1323         PK11SlotInfo * slot = NULL;
1324         PK11GenericObject *key;
1325         CK_ATTRIBUTE attrs[3];
1326         CK_BBOOL cktrue = CK_TRUE;
1327         CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
1328         int retcode = 0;
1329         PRFileInfo fi;
1330         PRStatus status;
1331
1332         memset( &fi, 0, sizeof(fi) );
1333         status = PR_GetFileInfo( filename, &fi );
1334         if ( PR_SUCCESS != status) {
1335                 PRErrorCode errcode = PR_GetError();
1336                 Debug( LDAP_DEBUG_ANY,
1337                            "TLS: could not read key file %s - error %d:%s.\n",
1338                            filename, errcode,
1339                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1340                 return -1;
1341         }
1342
1343         if ( fi.type != PR_FILE_FILE ) {
1344                 PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
1345                 Debug( LDAP_DEBUG_ANY,
1346                            "TLS: error: the key file %s is not a file.\n",
1347                            filename, 0 ,0 );
1348                 return -1;
1349         }
1350
1351         slot = PK11_FindSlotByName( TLSM_PEM_SLOT_CERTS );
1352
1353         if ( !slot ) {
1354                 PRErrorCode errcode = PR_GetError();
1355                 Debug( LDAP_DEBUG_ANY,
1356                            "TLS: could not find the slot for the private key '%s' - error %d:%s.\n",
1357                            filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1358                 return -1;
1359         }
1360
1361         PK11_SETATTRS( attrs[0], CKA_CLASS, &objClass, sizeof(objClass) );
1362         PK11_SETATTRS( attrs[1], CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) );
1363         PK11_SETATTRS( attrs[2], CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 );
1364
1365         key = PK11_CreateGenericObject( slot, attrs, 3, PR_FALSE /* isPerm */ );
1366
1367         if ( !key ) {
1368                 PRErrorCode errcode = PR_GetError();
1369                 Debug( LDAP_DEBUG_ANY,
1370                            "TLS: could not add the private key '%s' - error %d:%s.\n",
1371                            filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1372                 retcode = -1;
1373         } else {
1374                 tlsm_add_pem_obj( ctx, key );
1375                 retcode = 0;
1376
1377                 /* When adding an encrypted key the PKCS#11 will be set as removed */
1378                 /* This will force the token to be seen as re-inserted */
1379                 SECMOD_WaitForAnyTokenEvent( pem_module, 0, 0 );
1380                 PK11_IsPresent( slot );
1381         }
1382
1383         PK11_FreeSlot( slot );
1384
1385         return retcode;
1386 }
1387
1388 static int
1389 tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir )
1390 {
1391         PRBool isca = PR_TRUE;
1392         PRStatus status = PR_SUCCESS;
1393         PRErrorCode errcode = PR_SUCCESS;
1394
1395         if ( !cacertfile && !cacertdir ) {
1396                 /* no checking - not good, but allowed */
1397                 return 0;
1398         }
1399
1400         if ( cacertfile ) {
1401                 int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca );
1402                 if ( rc ) {
1403                         errcode = PR_GetError();
1404                         Debug( LDAP_DEBUG_ANY,
1405                                    "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
1406                                    cacertfile, errcode,
1407                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1408                         /* failure with cacertfile is a hard failure even if cacertdir is
1409                            also specified and contains valid CA cert files */
1410                         status = PR_FAILURE;
1411                 } else {
1412                         Debug( LDAP_DEBUG_TRACE,
1413                                    "TLS: loaded CA certificate file %s.\n",
1414                                    cacertfile, 0, 0 );
1415                 }
1416         }
1417
1418         /* if cacertfile above failed, we will return failure, even
1419            if there is a valid CA cert in cacertdir - but we still
1420            process cacertdir in case the user has enabled trace level
1421            debugging so they can see the processing for cacertdir too */
1422         /* any cacertdir failures are "soft" failures - if the user specifies
1423            no cert checking, then we allow the tls/ssl to continue, no matter
1424            what was specified for cacertdir, or the contents of the directory
1425            - this is different behavior than that of cacertfile */
1426         if ( cacertdir ) {
1427                 PRFileInfo fi;
1428                 PRDir *dir;
1429                 PRDirEntry *entry;
1430                 PRStatus fistatus = PR_FAILURE;
1431
1432                 memset( &fi, 0, sizeof(fi) );
1433                 fistatus = PR_GetFileInfo( cacertdir, &fi );
1434                 if ( PR_SUCCESS != fistatus) {
1435                         errcode = PR_GetError();
1436                         Debug( LDAP_DEBUG_ANY,
1437                                    "TLS: could not get info about the CA certificate directory %s - error %d:%s.\n",
1438                                    cacertdir, errcode,
1439                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1440                         goto done;
1441                 }
1442
1443                 if ( fi.type != PR_FILE_DIRECTORY ) {
1444                         Debug( LDAP_DEBUG_ANY,
1445                                    "TLS: error: the CA certificate directory %s is not a directory.\n",
1446                                    cacertdir, 0 ,0 );
1447                         goto done;
1448                 }
1449
1450                 dir = PR_OpenDir( cacertdir );
1451                 if ( NULL == dir ) {
1452                         errcode = PR_GetError();
1453                         Debug( LDAP_DEBUG_ANY,
1454                                    "TLS: could not open the CA certificate directory %s - error %d:%s.\n",
1455                                    cacertdir, errcode,
1456                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1457                         goto done;
1458                 }
1459
1460                 do {
1461                         entry = PR_ReadDir( dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN );
1462                         if ( ( NULL != entry ) && ( NULL != entry->name ) ) {
1463                                 char *fullpath = NULL;
1464                                 char *ptr;
1465
1466                                 ptr = PL_strrstr( entry->name, PEM_CA_HASH_FILE_SUFFIX );
1467                                 if ( ( ptr == NULL ) || ( *(ptr + PEM_CA_HASH_FILE_SUFFIX_LEN) != '\0' ) ) {
1468                                         Debug( LDAP_DEBUG_TRACE,
1469                                                    "TLS: file %s does not end in [%s] - does not appear to be a CA certificate "
1470                                                    "directory file with a properly hashed file name - skipping.\n",
1471                                                    entry->name, PEM_CA_HASH_FILE_SUFFIX, 0 );
1472                                         continue;
1473                                 }
1474                                 fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
1475                                 if ( !tlsm_add_cert_from_file( ctx, fullpath, isca ) ) {
1476                                         Debug( LDAP_DEBUG_TRACE,
1477                                                    "TLS: loaded CA certificate file %s from CA certificate directory %s.\n",
1478                                                    fullpath, cacertdir, 0 );
1479                                 } else {
1480                                         errcode = PR_GetError();
1481                                         Debug( LDAP_DEBUG_TRACE,
1482                                                    "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
1483                                                    fullpath, errcode,
1484                                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1485                                 }
1486                                 PR_smprintf_free( fullpath );
1487                         }
1488                 } while ( NULL != entry );
1489                 PR_CloseDir( dir );
1490         }
1491 done:
1492         if ( status != PR_SUCCESS ) {
1493                 return -1;
1494         }
1495
1496         return 0;
1497 }
1498
1499 /*
1500  * NSS supports having multiple cert/key databases in the same
1501  * directory, each one having a unique string prefix e.g.
1502  * slapd-01-cert8.db - the prefix here is "slapd-01-"
1503  * this function examines the given certdir - if it looks like
1504  * /path/to/directory/prefix it will return the
1505  * /path/to/directory part in realcertdir, and the prefix in prefix
1506  */
1507 static void
1508 tlsm_get_certdb_prefix( const char *certdir, char **realcertdir, char **prefix )
1509 {
1510         char sep = PR_GetDirectorySeparator();
1511         char *ptr = NULL;
1512         struct PRFileInfo prfi;
1513         PRStatus prc;
1514
1515         *realcertdir = (char *)certdir; /* default is the one passed in */
1516
1517         /* if certdir is not given, just return */
1518         if ( !certdir ) {
1519                 return;
1520         }
1521
1522         prc = PR_GetFileInfo( certdir, &prfi );
1523         /* if certdir exists (file or directory) then it cannot specify a prefix */
1524         if ( prc == PR_SUCCESS ) {
1525                 return;
1526         }
1527
1528         /* if certdir was given, and there is a '/' in certdir, see if there
1529            is anything after the last '/' - if so, assume it is the prefix */
1530         if ( ( ( ptr = strrchr( certdir, sep ) ) ) && *(ptr+1) ) {
1531                 *realcertdir = PL_strndup( certdir, ptr-certdir );
1532                 *prefix = PL_strdup( ptr+1 );
1533         }
1534
1535         return;
1536 }
1537
1538 /*
1539  * Currently mutiple MozNSS contexts share one certificate storage. When the
1540  * certdb is being opened, only new certificates are added to the storage.
1541  * When different databases are used, conflicting nicknames make the
1542  * certificate lookup by the nickname impossible. In addition a token
1543  * description might be prepended in certain conditions.
1544  *
1545  * In order to make the certificate lookup by nickname possible, we explicitly
1546  * open each database using SECMOD_OpenUserDB and assign it the token
1547  * description. The token description is generated using ctx->tc_unique value,
1548  * which is unique for each context.
1549  */
1550 static PK11SlotInfo *
1551 tlsm_init_open_certdb(tlsm_ctx *ctx, const char *dbdir, const char *prefix)
1552 {
1553         PK11SlotInfo *slot = NULL;
1554         char *token_desc = NULL;
1555         char *config = NULL;
1556
1557         token_desc = PR_smprintf(TLSM_CERTDB_DESC_FMT, ctx->tc_unique);
1558         config = PR_smprintf("configDir='%s' tokenDescription='%s' certPrefix='%s' keyPrefix='%s' flags=readOnly",
1559                                                                                 dbdir, token_desc, prefix, prefix);
1560         Debug(LDAP_DEBUG_TRACE, "TLS: certdb config: %s\n", config, 0, 0);
1561
1562         slot = SECMOD_OpenUserDB(config);
1563         if (!slot) {
1564                 PRErrorCode errcode = PR_GetError();
1565                 Debug(LDAP_DEBUG_TRACE, "TLS: cannot open certdb '%s', error %d:%s\n", dbdir, errcode,
1566                                                         PR_ErrorToString(errcode, PR_LANGUAGE_I_DEFAULT));
1567         }
1568
1569         if (token_desc)
1570                 PR_smprintf_free(token_desc);
1571         if (config)
1572                 PR_smprintf_free(config);
1573
1574         return slot;
1575 }
1576
1577 /*
1578  * This is the part of the init we defer until we get the
1579  * actual security configuration information.  This is
1580  * only called once, protected by a PRCallOnce
1581  * NOTE: This must be done before the first call to SSL_ImportFD,
1582  * especially the setting of the policy
1583  * NOTE: This must be called after fork()
1584  */
1585 static int
1586 tlsm_deferred_init( void *arg )
1587 {
1588         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1589         struct ldaptls *lt = ctx->tc_config;
1590         const char *securitydirs[3];
1591         int ii;
1592         int nn;
1593         PRErrorCode errcode = 1;
1594 #ifdef HAVE_NSS_INITCONTEXT
1595         NSSInitParameters initParams;
1596         NSSInitContext *initctx = NULL;
1597         PK11SlotInfo *certdb_slot = NULL;
1598 #endif
1599         SECStatus rc;
1600         int done = 0;
1601
1602 #ifdef HAVE_SECMOD_RESTARTMODULES
1603         /* NSS enforces the pkcs11 requirement that modules should be unloaded after
1604            a fork() - since there is no portable way to determine if NSS has been
1605            already initialized in a parent process, we just call SECMOD_RestartModules
1606            with force == FALSE - if the module has been unloaded due to a fork, it will
1607            be reloaded, otherwise, it is a no-op */
1608         if ( SECFailure == ( rc = SECMOD_RestartModules(PR_FALSE /* do not force */) ) ) {
1609                 errcode = PORT_GetError();
1610                 if ( errcode != SEC_ERROR_NOT_INITIALIZED ) {
1611                         Debug( LDAP_DEBUG_TRACE,
1612                                    "TLS: could not restart the security modules: %d:%s\n",
1613                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1614                 } else {
1615                         errcode = 1;
1616                 }
1617         }
1618 #endif
1619
1620 #ifdef HAVE_NSS_INITCONTEXT
1621         memset( &initParams, 0, sizeof( initParams ) );
1622         initParams.length = sizeof( initParams );
1623 #endif /* HAVE_NSS_INITCONTEXT */
1624
1625 #ifdef LDAP_R_COMPILE
1626         if ( PR_CallOnce( &tlsm_init_mutex_callonce, tlsm_thr_init_callonce ) ) {
1627                 return -1;
1628         }
1629 #endif /* LDAP_R_COMPILE */
1630
1631 #ifndef HAVE_NSS_INITCONTEXT
1632         if ( !NSS_IsInitialized() ) {
1633 #endif /* HAVE_NSS_INITCONTEXT */
1634                 /*
1635                   MOZNSS_DIR will override everything else - you can
1636                   always set MOZNSS_DIR to force the use of this
1637                   directory
1638                   If using MOZNSS, specify the location of the moznss db dir
1639                   in the cacertdir directive of the OpenLDAP configuration.
1640                   DEFAULT_MOZNSS_DIR will only be used if the code cannot
1641                   find a security dir to use based on the current
1642                   settings
1643                 */
1644                 nn = 0;
1645                 securitydirs[nn++] = PR_GetEnv( "MOZNSS_DIR" );
1646                 securitydirs[nn++] = lt->lt_cacertdir;
1647                 securitydirs[nn++] = PR_GetEnv( "DEFAULT_MOZNSS_DIR" );
1648                 for ( ii = 0; !done && ( ii < nn ); ++ii ) {
1649                         char *realcertdir = NULL;
1650                         const char *defprefix = "";
1651                         char *prefix = (char *)defprefix;
1652                         const char *securitydir = securitydirs[ii];
1653                         if ( NULL == securitydir ) {
1654                                 continue;
1655                         }
1656
1657                         tlsm_get_certdb_prefix( securitydir, &realcertdir, &prefix );
1658
1659                         /* initialize only moddb; certdb will be initialized explicitly */
1660 #ifdef HAVE_NSS_INITCONTEXT
1661 #ifdef INITCONTEXT_HACK
1662                         if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
1663                                 rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
1664                         } else {
1665                                 initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
1666                                                                    &initParams, NSS_INIT_READONLY|NSS_INIT_NOCERTDB );
1667                         }
1668 #else
1669                         initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
1670                                                                    &initParams, NSS_INIT_READONLY|NSS_INIT_NOCERTDB );
1671 #endif
1672                         rc = SECFailure;
1673
1674                         if (initctx != NULL) {
1675                                 certdb_slot = tlsm_init_open_certdb(ctx, realcertdir, prefix);
1676                                 if (certdb_slot) {
1677                                         rc = SECSuccess;
1678                                         ctx->tc_initctx = initctx;
1679                                         ctx->tc_certdb_slot = certdb_slot;
1680                                 } else {
1681                                         NSS_ShutdownContext(initctx);
1682                                         initctx = NULL;
1683                                 }
1684                         }
1685 #else
1686                         rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
1687 #endif
1688
1689                         if ( rc != SECSuccess ) {
1690                                 errcode = PORT_GetError();
1691                                 if ( securitydirs[ii] != lt->lt_cacertdir) {
1692                                         Debug( LDAP_DEBUG_TRACE,
1693                                                    "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
1694                                                    realcertdir, prefix, errcode );
1695                                 }
1696                         } else {
1697                                 /* success */
1698                                 Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s prefix %s.\n",
1699                                            realcertdir, prefix, 0 );
1700                                 errcode = 0;
1701                                 done = 1;
1702                         }
1703                         if ( realcertdir != securitydir ) {
1704                                 PL_strfree( realcertdir );
1705                         }
1706                         if ( prefix != defprefix ) {
1707                                 PL_strfree( prefix );
1708                         }
1709                 }
1710
1711                 if ( errcode ) { /* no moznss db found, or not using moznss db */
1712 #ifdef HAVE_NSS_INITCONTEXT
1713                         int flags = NSS_INIT_READONLY|NSS_INIT_NOCERTDB|NSS_INIT_NOMODDB;
1714 #ifdef INITCONTEXT_HACK
1715                         if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
1716                                 rc = NSS_NoDB_Init( NULL );
1717                         } else {
1718                                 initctx = NSS_InitContext( CERTDB_NONE, PREFIX_NONE, PREFIX_NONE, SECMOD_DB,
1719                                                                                    &initParams, flags );
1720                                 rc = (initctx == NULL) ? SECFailure : SECSuccess;
1721                         }
1722 #else
1723                         initctx = NSS_InitContext( CERTDB_NONE, PREFIX_NONE, PREFIX_NONE, SECMOD_DB,
1724                                                                            &initParams, flags );
1725                         if (initctx) {
1726                                 ctx->tc_initctx = initctx;
1727                                 rc = SECSuccess;
1728                         } else {
1729                                 rc = SECFailure;
1730                         }
1731 #endif
1732 #else
1733                         rc = NSS_NoDB_Init( NULL );
1734 #endif
1735                         if ( rc != SECSuccess ) {
1736                                 errcode = PORT_GetError();
1737                                 Debug( LDAP_DEBUG_ANY,
1738                                            "TLS: could not initialize moznss - error %d:%s.\n",
1739                                            errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1740                                 return -1;
1741                         }
1742                 }
1743
1744                 if ( errcode || lt->lt_cacertfile ) {
1745                         /* initialize the PEM module */
1746                         if ( tlsm_init_pem_module() ) {
1747                                 int pem_errcode = PORT_GetError();
1748                                 Debug( LDAP_DEBUG_ANY,
1749                                            "TLS: could not initialize moznss PEM module - error %d:%s.\n",
1750                                            pem_errcode, PR_ErrorToString( pem_errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1751
1752                                 if ( errcode ) /* PEM is required */
1753                                         return -1;
1754
1755                         } else if ( !errcode ) {
1756                                 tlsm_init_ca_certs( ctx, lt->lt_cacertfile, NULL );
1757                         }
1758                 }
1759
1760                 if ( errcode ) {
1761                         if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) {
1762                                 /* if we tried to use lt->lt_cacertdir as an NSS key/cert db, errcode 
1763                                    will be a value other than 1 - print an error message so that the
1764                                    user will know that failed too */
1765                                 if ( ( errcode != 1 ) && ( lt->lt_cacertdir ) ) {
1766                                         char *realcertdir = NULL;
1767                                         char *prefix = NULL;
1768                                         tlsm_get_certdb_prefix( lt->lt_cacertdir, &realcertdir, &prefix );
1769                                         Debug( LDAP_DEBUG_TRACE,
1770                                                    "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
1771                                                    realcertdir, prefix ? prefix : "", errcode );
1772                                         if ( realcertdir != lt->lt_cacertdir ) {
1773                                                 PL_strfree( realcertdir );
1774                                         }
1775                                         PL_strfree( prefix );
1776                                 }
1777                                 return -1;
1778                         }
1779
1780                         ctx->tc_using_pem = PR_TRUE;
1781                 }
1782
1783                 NSS_SetDomesticPolicy();
1784
1785                 PK11_SetPasswordFunc( tlsm_pin_prompt );
1786
1787                 /* register cleanup function */
1788                 if ( tlsm_register_nss_shutdown() ) {
1789                         errcode = PORT_GetError();
1790                         Debug( LDAP_DEBUG_ANY,
1791                                    "TLS: could not register NSS shutdown function: %d:%s\n",
1792                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1793                         return -1;
1794                 }
1795
1796                 if  ( ctx->tc_is_server ) {
1797                         /* 0 means use the defaults here */
1798                         SSL_ConfigServerSessionIDCache( 0, 0, 0, NULL );
1799                 }
1800
1801 #ifndef HAVE_NSS_INITCONTEXT
1802         }
1803 #endif /* HAVE_NSS_INITCONTEXT */
1804
1805         return 0;
1806 }
1807
1808 /*
1809  * Find and verify the certificate.
1810  * The key is loaded and stored in ctx->tc_private_key
1811  */
1812 static int
1813 tlsm_find_and_verify_cert_key(tlsm_ctx *ctx)
1814 {
1815         SECCertificateUsage certUsage;
1816         PRBool checkSig;
1817         SECStatus status;
1818         int errorToIgnore;
1819         void *pin_arg;
1820
1821         if (tlsm_ctx_load_private_key(ctx))
1822                 return -1;
1823
1824         pin_arg = SSL_RevealPinArg(ctx->tc_model);
1825         certUsage = ctx->tc_is_server ? certificateUsageSSLServer : certificateUsageSSLClient;
1826         checkSig = ctx->tc_verify_cert ? PR_TRUE : PR_FALSE;
1827         if ( ctx->tc_warn_only )
1828                 errorToIgnore = -1;
1829         else
1830                 errorToIgnore = SEC_ERROR_UNKNOWN_ISSUER; /* may not have a CA cert */
1831
1832         status = tlsm_verify_cert( ctx->tc_certdb, ctx->tc_certificate, pin_arg,
1833                                                            checkSig, certUsage, errorToIgnore );
1834
1835         return status == SECSuccess ? 0 : -1;
1836 }
1837
1838 static int
1839 tlsm_get_client_auth_data( void *arg, PRFileDesc *fd,
1840                                                    CERTDistNames *caNames, CERTCertificate **pRetCert,
1841                                                    SECKEYPrivateKey **pRetKey )
1842 {
1843         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1844
1845         if (pRetCert)
1846                 *pRetCert = CERT_DupCertificate(ctx->tc_certificate);
1847
1848         if (pRetKey)
1849                 *pRetKey = SECKEY_CopyPrivateKey(ctx->tc_private_key);
1850
1851         return SECSuccess;
1852 }
1853
1854 /*
1855  * ctx must have a tc_model that is valid
1856 */
1857 static int
1858 tlsm_clientauth_init( tlsm_ctx *ctx )
1859 {
1860         SECStatus status = SECFailure;
1861         int rc;
1862         PRBool saveval;
1863
1864         saveval = ctx->tc_warn_only;
1865         ctx->tc_warn_only = PR_TRUE;
1866         rc = tlsm_find_and_verify_cert_key(ctx);
1867         ctx->tc_warn_only = saveval;
1868         if ( rc ) {
1869                 Debug( LDAP_DEBUG_ANY,
1870                            "TLS: error: unable to set up client certificate authentication for "
1871                            "certificate named %s\n", tlsm_ctx_subject_name(ctx), 0, 0 );
1872                 return -1;
1873         }
1874
1875         status = SSL_GetClientAuthDataHook( ctx->tc_model,
1876                                                                                 tlsm_get_client_auth_data,
1877                                                                                 (void *)ctx );
1878
1879         return ( status == SECSuccess ? 0 : -1 );
1880 }
1881
1882 /*
1883  * Tear down the TLS subsystem. Should only be called once.
1884  */
1885 static void
1886 tlsm_destroy( void )
1887 {
1888 #ifdef LDAP_R_COMPILE
1889         ldap_pvt_thread_mutex_destroy( &tlsm_ctx_count_mutex );
1890         ldap_pvt_thread_mutex_destroy( &tlsm_init_mutex );
1891         ldap_pvt_thread_mutex_destroy( &tlsm_pem_mutex );
1892 #endif
1893 }
1894
1895 static struct ldaptls *
1896 tlsm_copy_config ( const struct ldaptls *config )
1897 {
1898         struct ldaptls *copy;
1899
1900         assert(config);
1901
1902         copy = LDAP_MALLOC(sizeof(*copy));
1903         if (!copy)
1904                 return NULL;
1905
1906         memset(copy, 0, sizeof(*copy));
1907
1908         if (config->lt_certfile)
1909                 copy->lt_certfile = LDAP_STRDUP(config->lt_certfile);
1910         if (config->lt_keyfile)
1911                 copy->lt_keyfile = LDAP_STRDUP(config->lt_keyfile);
1912         if (config->lt_dhfile)
1913                 copy->lt_dhfile = LDAP_STRDUP(config->lt_dhfile);
1914         if (config->lt_cacertfile)
1915                 copy->lt_cacertfile = LDAP_STRDUP(config->lt_cacertfile);
1916         if (config->lt_cacertdir)
1917                 copy->lt_cacertdir = LDAP_STRDUP(config->lt_cacertdir);
1918         if (config->lt_ciphersuite)
1919                 copy->lt_ciphersuite = LDAP_STRDUP(config->lt_ciphersuite);
1920         if (config->lt_crlfile)
1921                 copy->lt_crlfile = LDAP_STRDUP(config->lt_crlfile);
1922         if (config->lt_randfile)
1923                 copy->lt_randfile = LDAP_STRDUP(config->lt_randfile);
1924
1925         copy->lt_protocol_min = config->lt_protocol_min;
1926
1927         return copy;
1928 }
1929
1930 static void
1931 tlsm_free_config ( struct ldaptls *config )
1932 {
1933         assert(config);
1934
1935         if (config->lt_certfile)
1936                 LDAP_FREE(config->lt_certfile);
1937         if (config->lt_keyfile)
1938                 LDAP_FREE(config->lt_keyfile);
1939         if (config->lt_dhfile)
1940                 LDAP_FREE(config->lt_dhfile);
1941         if (config->lt_cacertfile)
1942                 LDAP_FREE(config->lt_cacertfile);
1943         if (config->lt_cacertdir)
1944                 LDAP_FREE(config->lt_cacertdir);
1945         if (config->lt_ciphersuite)
1946                 LDAP_FREE(config->lt_ciphersuite);
1947         if (config->lt_crlfile)
1948                 LDAP_FREE(config->lt_crlfile);
1949         if (config->lt_randfile)
1950                 LDAP_FREE(config->lt_randfile);
1951
1952         LDAP_FREE(config);
1953 }
1954
1955 static tls_ctx *
1956 tlsm_ctx_new ( struct ldapoptions *lo )
1957 {
1958         tlsm_ctx *ctx;
1959
1960         ctx = LDAP_MALLOC( sizeof (*ctx) );
1961         if ( ctx ) {
1962                 ctx->tc_refcnt = 1;
1963 #ifdef LDAP_R_COMPILE
1964                 ldap_pvt_thread_mutex_init( &ctx->tc_refmutex );
1965 #endif
1966                 LDAP_MUTEX_LOCK( &tlsm_ctx_count_mutex );
1967                 ctx->tc_unique = tlsm_ctx_count++;
1968                 LDAP_MUTEX_UNLOCK( &tlsm_ctx_count_mutex );
1969                 ctx->tc_config = NULL; /* populated later by tlsm_ctx_init */
1970                 ctx->tc_certdb = NULL;
1971                 ctx->tc_certdb_slot = NULL;
1972                 ctx->tc_certificate = NULL;
1973                 ctx->tc_private_key = NULL;
1974                 ctx->tc_pin_file = NULL;
1975                 ctx->tc_model = NULL;
1976                 memset(&ctx->tc_callonce, 0, sizeof(ctx->tc_callonce));
1977                 ctx->tc_require_cert = lo->ldo_tls_require_cert;
1978                 ctx->tc_verify_cert = PR_FALSE;
1979                 ctx->tc_using_pem = PR_FALSE;
1980 #ifdef HAVE_NSS_INITCONTEXT
1981                 ctx->tc_initctx = NULL;
1982 #endif /* HAVE_NSS_INITCONTEXT */
1983                 ctx->tc_pem_objs = NULL;
1984                 ctx->tc_n_pem_objs = 0;
1985                 ctx->tc_warn_only = PR_FALSE;
1986         }
1987         return (tls_ctx *)ctx;
1988 }
1989
1990 static void
1991 tlsm_ctx_ref( tls_ctx *ctx )
1992 {
1993         tlsm_ctx *c = (tlsm_ctx *)ctx;
1994         LDAP_MUTEX_LOCK( &c->tc_refmutex );
1995         c->tc_refcnt++;
1996         LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
1997 }
1998
1999 static void
2000 tlsm_ctx_free ( tls_ctx *ctx )
2001 {
2002         tlsm_ctx *c = (tlsm_ctx *)ctx;
2003         int refcount;
2004
2005         if ( !c ) return;
2006
2007         LDAP_MUTEX_LOCK( &c->tc_refmutex );
2008         refcount = --c->tc_refcnt;
2009         LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
2010         if ( refcount )
2011                 return;
2012
2013         LDAP_MUTEX_LOCK( &tlsm_init_mutex );
2014         if ( c->tc_model )
2015                 PR_Close( c->tc_model );
2016         if (c->tc_certificate)
2017                 CERT_DestroyCertificate(c->tc_certificate);
2018         if (c->tc_private_key)
2019                 SECKEY_DestroyPrivateKey(c->tc_private_key);
2020         c->tc_certdb = NULL; /* if not the default, may have to clean up */
2021         if ( c->tc_certdb_slot ) {
2022                 if ( SECMOD_CloseUserDB( c->tc_certdb_slot ) ) {
2023                         PRErrorCode errcode = PR_GetError();
2024                         Debug( LDAP_DEBUG_ANY,
2025                                    "TLS: could not close certdb slot - error %d:%s.\n",
2026                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
2027                 }
2028         }
2029         PL_strfree( c->tc_pin_file );
2030         c->tc_pin_file = NULL;
2031         tlsm_free_pem_objs( c );
2032 #ifdef HAVE_NSS_INITCONTEXT
2033         if ( c->tc_initctx ) {
2034                 if ( NSS_ShutdownContext( c->tc_initctx ) ) {
2035                         PRErrorCode errcode = PR_GetError();
2036                         Debug( LDAP_DEBUG_ANY,
2037                                    "TLS: could not shutdown NSS - error %d:%s.\n",
2038                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
2039                 }
2040         }
2041         c->tc_initctx = NULL;
2042 #endif /* HAVE_NSS_INITCONTEXT */
2043         LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
2044 #ifdef LDAP_R_COMPILE
2045         ldap_pvt_thread_mutex_destroy( &c->tc_refmutex );
2046 #endif
2047
2048         if ( c->tc_config )
2049                 tlsm_free_config( c->tc_config );
2050
2051         LDAP_FREE( c );
2052 }
2053
2054 /*
2055  * initialize a new TLS context
2056  */
2057 static int
2058 tlsm_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
2059 {
2060         tlsm_ctx *ctx = (tlsm_ctx *)lo->ldo_tls_ctx;
2061         ctx->tc_config = tlsm_copy_config(lt);
2062         ctx->tc_is_server = is_server;
2063
2064         return 0;
2065 }
2066
2067 static int
2068 tlsm_deferred_ctx_init( void *arg )
2069 {
2070         tlsm_ctx *ctx = (tlsm_ctx *)arg;
2071         PRBool sslv2 = PR_FALSE;
2072         PRBool sslv3 = PR_TRUE;
2073         PRBool tlsv1 = PR_TRUE;
2074         PRBool request_cert = PR_FALSE;
2075         PRInt32 require_cert = PR_FALSE;
2076         PRFileDesc *fd;
2077         struct ldaptls *lt;
2078
2079         if ( tlsm_deferred_init( ctx ) ) {
2080             Debug( LDAP_DEBUG_ANY,
2081                            "TLS: could not perform TLS system initialization.\n",
2082                            0, 0, 0 );
2083             return -1;
2084         }
2085
2086         ctx->tc_certdb = CERT_GetDefaultCertDB(); /* If there is ever a per-context db, change this */
2087
2088         fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
2089         if ( fd ) {
2090                 ctx->tc_model = SSL_ImportFD( NULL, fd );
2091         }
2092
2093         if ( !ctx->tc_model ) {
2094                 PRErrorCode err = PR_GetError();
2095                 Debug( LDAP_DEBUG_ANY,
2096                            "TLS: could perform TLS socket I/O layer initialization - error %d:%s.\n",
2097                            err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2098
2099                 if ( fd ) {
2100                         PR_Close( fd );
2101                 }
2102                 return -1;
2103         }
2104
2105         if ( SSL_SetPKCS11PinArg(ctx->tc_model, ctx) ) {
2106                 Debug( LDAP_DEBUG_ANY,
2107                                 "TLS: could not set pin prompt argument\n", 0, 0, 0);
2108                 return -1;
2109         }
2110
2111         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_SECURITY, PR_TRUE ) ) {
2112                 Debug( LDAP_DEBUG_ANY,
2113                        "TLS: could not set secure mode on.\n",
2114                        0, 0, 0 );
2115                 return -1;
2116         }
2117
2118         lt = ctx->tc_config;
2119
2120         /* default is sslv3 and tlsv1 */
2121         if ( lt->lt_protocol_min ) {
2122                 if ( lt->lt_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 ) {
2123                         sslv3 = PR_FALSE;
2124                 } else if ( lt->lt_protocol_min <= LDAP_OPT_X_TLS_PROTOCOL_SSL2 ) {
2125                         sslv2 = PR_TRUE;
2126                         Debug( LDAP_DEBUG_ANY,
2127                                "TLS: warning: minimum TLS protocol level set to "
2128                                "include SSLv2 - SSLv2 is insecure - do not use\n", 0, 0, 0 );
2129                 }
2130         }
2131         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL2, sslv2 ) ) {
2132                 Debug( LDAP_DEBUG_ANY,
2133                        "TLS: could not set SSLv2 mode on.\n",
2134                        0, 0, 0 );
2135                 return -1;
2136         }
2137         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL3, sslv3 ) ) {
2138                 Debug( LDAP_DEBUG_ANY,
2139                        "TLS: could not set SSLv3 mode on.\n",
2140                        0, 0, 0 );
2141                 return -1;
2142         }
2143         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_TLS, tlsv1 ) ) {
2144                 Debug( LDAP_DEBUG_ANY,
2145                        "TLS: could not set TLSv1 mode on.\n",
2146                        0, 0, 0 );
2147                 return -1;
2148         }
2149
2150         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_CLIENT, !ctx->tc_is_server ) ) {
2151                 Debug( LDAP_DEBUG_ANY,
2152                        "TLS: could not set handshake as client.\n",
2153                        0, 0, 0 );
2154                 return -1;
2155         }
2156         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_SERVER, ctx->tc_is_server ) ) {
2157                 Debug( LDAP_DEBUG_ANY,
2158                        "TLS: could not set handshake as server.\n",
2159                        0, 0, 0 );
2160                 return -1;
2161         }
2162
2163         if ( lt->lt_ciphersuite ) {
2164                 if ( tlsm_parse_ciphers( ctx, lt->lt_ciphersuite ) ) {
2165                         Debug( LDAP_DEBUG_ANY,
2166                                "TLS: could not set cipher list %s.\n",
2167                                lt->lt_ciphersuite, 0, 0 );
2168                         return -1;
2169                 }
2170         } else if ( tlsm_parse_ciphers( ctx, "DEFAULT" ) ) {
2171                 Debug( LDAP_DEBUG_ANY,
2172                        "TLS: could not set cipher list DEFAULT.\n",
2173                        0, 0, 0 );
2174                 return -1;
2175         }
2176
2177         if ( !ctx->tc_require_cert ) {
2178                 ctx->tc_verify_cert = PR_FALSE;
2179         } else if ( !ctx->tc_is_server ) {
2180                 request_cert = PR_TRUE;
2181                 require_cert = SSL_REQUIRE_NO_ERROR;
2182                 if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
2183                      ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
2184                         require_cert = SSL_REQUIRE_ALWAYS;
2185                 }
2186                 if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW )
2187                         ctx->tc_verify_cert = PR_TRUE;
2188         } else { /* server */
2189                 /* server does not request certs by default */
2190                 /* if allow - client may send cert, server will ignore if errors */
2191                 /* if try - client may send cert, server will error if bad cert */
2192                 /* if hard or demand - client must send cert, server will error if bad cert */
2193                 request_cert = PR_TRUE;
2194                 require_cert = SSL_REQUIRE_NO_ERROR;
2195                 if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
2196                      ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
2197                         require_cert = SSL_REQUIRE_ALWAYS;
2198                 }
2199                 if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW ) {
2200                         ctx->tc_verify_cert = PR_TRUE;
2201                 } else {
2202                         ctx->tc_warn_only = PR_TRUE;
2203                 }
2204         }
2205
2206         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUEST_CERTIFICATE, request_cert ) ) {
2207                 Debug( LDAP_DEBUG_ANY,
2208                        "TLS: could not set request certificate mode.\n",
2209                        0, 0, 0 );
2210                 return -1;
2211         }
2212                 
2213         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUIRE_CERTIFICATE, require_cert ) ) {
2214                 Debug( LDAP_DEBUG_ANY,
2215                        "TLS: could not set require certificate mode.\n",
2216                        0, 0, 0 );
2217                 return -1;
2218         }
2219
2220         /* set up our cert and key, if any */
2221         if ( lt->lt_certfile ) {
2222                 /* if using the PEM module, load the PEM file specified by lt_certfile */
2223                 /* otherwise, assume this is the name of a cert already in the db */
2224                 if ( ctx->tc_using_pem ) {
2225                         /* this sets ctx->tc_certificate to the correct value */
2226                         int rc = tlsm_add_cert_from_file( ctx, lt->lt_certfile, PR_FALSE );
2227                         if ( rc ) {
2228                                 return rc;
2229                         }
2230                 } else {
2231                         char *tmp_certname;
2232
2233                         if (ctx->tc_certdb_slot) {
2234                                 tmp_certname = PR_smprintf(TLSM_CERTDB_DESC_FMT ":%s", ctx->tc_unique, lt->lt_certfile);
2235                         } else {
2236                                 tmp_certname = PR_smprintf("%s", lt->lt_certfile);
2237                         }
2238
2239                         ctx->tc_certificate = PK11_FindCertFromNickname(tmp_certname, SSL_RevealPinArg(ctx->tc_model));
2240                         PR_smprintf_free(tmp_certname);
2241
2242                         if (!ctx->tc_certificate) {
2243                                 PRErrorCode errcode = PR_GetError();
2244                                 Debug( LDAP_DEBUG_ANY,
2245                                            "TLS: error: the certificate '%s' could not be found in the database - error %d:%s.\n",
2246                                            lt->lt_certfile, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
2247                                 return -1;
2248                         }
2249                 }
2250         }
2251
2252         if ( lt->lt_keyfile ) {
2253                 /* if using the PEM module, load the PEM file specified by lt_keyfile */
2254                 /* otherwise, assume this is the pininfo for the key */
2255                 if ( ctx->tc_using_pem ) {
2256                         int rc = tlsm_add_key_from_file( ctx, lt->lt_keyfile );
2257                         if ( rc ) {
2258                                 return rc;
2259                         }
2260                 } else {
2261                         PL_strfree( ctx->tc_pin_file );
2262                         ctx->tc_pin_file = PL_strdup( lt->lt_keyfile );
2263                 }
2264         }
2265
2266         /* Set up callbacks for use by clients */
2267         if ( !ctx->tc_is_server ) {
2268                 if ( SSL_OptionSet( ctx->tc_model, SSL_NO_CACHE, PR_TRUE ) != SECSuccess ) {
2269                         PRErrorCode err = PR_GetError();
2270                         Debug( LDAP_DEBUG_ANY, 
2271                                "TLS: error: could not set nocache option for moznss - error %d:%s\n",
2272                                err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2273                         return -1;
2274                 }
2275
2276                 if ( SSL_BadCertHook( ctx->tc_model, tlsm_bad_cert_handler, ctx ) != SECSuccess ) {
2277                         PRErrorCode err = PR_GetError();
2278                         Debug( LDAP_DEBUG_ANY, 
2279                                "TLS: error: could not set bad cert handler for moznss - error %d:%s\n",
2280                                err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2281                         return -1;
2282                 }
2283
2284                 /* 
2285                    since a cert has been specified, assume the client wants to do cert auth
2286                 */
2287                 if ( ctx->tc_certificate ) {
2288                         if ( tlsm_clientauth_init( ctx ) ) {
2289                                 Debug( LDAP_DEBUG_ANY, 
2290                                        "TLS: error: unable to set up client certificate authentication using '%s'\n",
2291                                        tlsm_ctx_subject_name(ctx), 0, 0 );
2292                                 return -1;
2293                         }
2294                 }
2295         } else { /* set up secure server */
2296                 SSLKEAType certKEA;
2297                 SECStatus status;
2298
2299                 /* must have a certificate for the server to use */
2300                 if ( !ctx->tc_certificate ) {
2301                         Debug( LDAP_DEBUG_ANY, 
2302                                "TLS: error: no server certificate: must specify a certificate for the server to use\n",
2303                                0, 0, 0 );
2304                         return -1;
2305                 }
2306
2307                 if (tlsm_find_and_verify_cert_key(ctx)) {
2308                         Debug( LDAP_DEBUG_ANY, 
2309                                "TLS: error: unable to find and verify server's cert and key for certificate %s\n",
2310                                tlsm_ctx_subject_name(ctx), 0, 0 );
2311                         return -1;
2312                 }
2313
2314                 /* configure the socket to be a secure server socket */
2315                 certKEA = NSS_FindCertKEAType( ctx->tc_certificate );
2316                 status = SSL_ConfigSecureServer( ctx->tc_model, ctx->tc_certificate, ctx->tc_private_key, certKEA );
2317
2318                 if ( SECSuccess != status ) {
2319                         PRErrorCode err = PR_GetError();
2320                         Debug( LDAP_DEBUG_ANY, 
2321                                "TLS: error: unable to configure secure server using certificate '%s' - error %d:%s\n",
2322                                tlsm_ctx_subject_name(ctx), err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
2323                         return -1;
2324                 }
2325         }
2326
2327         /* Callback for authenticating certificate */
2328         if ( SSL_AuthCertificateHook( ctx->tc_model, tlsm_auth_cert_handler,
2329                                   ctx ) != SECSuccess ) {
2330                 PRErrorCode err = PR_GetError();
2331                 Debug( LDAP_DEBUG_ANY, 
2332                        "TLS: error: could not set auth cert handler for moznss - error %d:%s\n",
2333                        err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2334                 return -1;
2335         }
2336
2337         if ( SSL_HandshakeCallback( ctx->tc_model, tlsm_handshake_complete_cb, ctx ) ) {
2338                 PRErrorCode err = PR_GetError();
2339                 Debug( LDAP_DEBUG_ANY, 
2340                        "TLS: error: could not set handshake callback for moznss - error %d:%s\n",
2341                        err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2342                 return -1;
2343         }
2344
2345         tlsm_free_config( ctx->tc_config );
2346         ctx->tc_config = NULL;
2347
2348         return 0;
2349 }
2350
2351 struct tls_data {
2352         tlsm_session            *session;
2353         Sockbuf_IO_Desc         *sbiod;
2354         /* there seems to be no portable way to determine if the
2355            sockbuf sd has been set to nonblocking mode - the
2356            call to ber_pvt_socket_set_nonblock() takes place
2357            before the tls socket is set up, so we cannot
2358            intercept that call either.
2359            On systems where fcntl is available, we can just
2360            F_GETFL and test for O_NONBLOCK.  On other systems,
2361            we will just see if the IO op returns EAGAIN or EWOULDBLOCK,
2362            and just set this flag */
2363         PRBool              nonblock;
2364         /*
2365          * NSS tries hard to be backwards compatible with SSLv2 clients, or
2366          * clients that send an SSLv2 client hello.  This message is not
2367          * tagged in any way, so NSS has no way to know if the incoming
2368          * message is a valid SSLv2 client hello or just some bogus data
2369          * (or cleartext LDAP).  We store the first byte read from the
2370          * client here.  The most common case will be a client sending
2371          * LDAP data instead of SSL encrypted LDAP data.  This can happen,
2372          * for example, if using ldapsearch -Z - if the starttls fails,
2373          * the client will fallback to plain cleartext LDAP.  So if we
2374          * see that the firstbyte is a valid LDAP tag, we can be
2375          * pretty sure this is happening.
2376          */
2377         ber_tag_t           firsttag;
2378         /*
2379          * NSS doesn't return SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, etc.
2380          * when it is blocked, so we have to set a flag in the wrapped send
2381          * and recv calls that tells us what operation NSS was last blocked
2382          * on
2383          */
2384 #define TLSM_READ  1
2385 #define TLSM_WRITE 2
2386         int io_flag;
2387 };
2388
2389 static struct tls_data *
2390 tlsm_get_pvt_tls_data( PRFileDesc *fd )
2391 {
2392         struct tls_data         *p;
2393         PRFileDesc *myfd;
2394
2395         if ( !fd ) {
2396                 return NULL;
2397         }
2398
2399         myfd = PR_GetIdentitiesLayer( fd, tlsm_layer_id );
2400
2401         if ( !myfd ) {
2402                 return NULL;
2403         }
2404
2405         p = (struct tls_data *)myfd->secret;
2406
2407         return p;
2408 }
2409
2410 static int
2411 tlsm_is_non_ssl_message( PRFileDesc *fd, ber_tag_t *thebyte )
2412 {
2413         struct tls_data         *p;
2414
2415         if ( thebyte ) {
2416                 *thebyte = LBER_DEFAULT;
2417         }
2418
2419         p = tlsm_get_pvt_tls_data( fd );
2420         if ( p == NULL || p->sbiod == NULL ) {
2421                 return 0;
2422         }
2423
2424         if ( p->firsttag == LBER_SEQUENCE ) {
2425                 if ( thebyte ) {
2426                         *thebyte = p->firsttag;
2427                 }
2428                 return 1;
2429         }
2430
2431         return 0;
2432 }
2433
2434 static tls_session *
2435 tlsm_session_new ( tls_ctx * ctx, int is_server )
2436 {
2437         tlsm_ctx *c = (tlsm_ctx *)ctx;
2438         tlsm_session *session;
2439         PRFileDesc *fd;
2440         PRStatus status;
2441         int rc;
2442
2443         c->tc_is_server = is_server;
2444         LDAP_MUTEX_LOCK( &tlsm_init_mutex );
2445         status = PR_CallOnceWithArg( &c->tc_callonce, tlsm_deferred_ctx_init, c );
2446         LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
2447         if ( PR_SUCCESS != status ) {
2448                 PRErrorCode err = PR_GetError();
2449                 Debug( LDAP_DEBUG_ANY, 
2450                        "TLS: error: could not initialize moznss security context - error %d:%s\n",
2451                        err, PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT), NULL );
2452                 return NULL;
2453         }
2454
2455         fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
2456         if ( !fd ) {
2457                 return NULL;
2458         }
2459
2460         session = SSL_ImportFD( c->tc_model, fd );
2461         if ( !session ) {
2462                 PR_DELETE( fd );
2463                 return NULL;
2464         }
2465
2466         rc = SSL_ResetHandshake( session, is_server );
2467         if ( rc ) {
2468                 PRErrorCode err = PR_GetError();
2469                 Debug( LDAP_DEBUG_TRACE, 
2470                            "TLS: error: new session - reset handshake failure %d - error %d:%s\n",
2471                            rc, err,
2472                            err ? PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) : "unknown" );
2473                 PR_DELETE( fd );
2474                 PR_Close( session );
2475                 session = NULL;
2476         }
2477
2478         return (tls_session *)session;
2479
2480
2481 static int
2482 tlsm_session_accept_or_connect( tls_session *session, int is_accept )
2483 {
2484         tlsm_session *s = (tlsm_session *)session;
2485         int rc;
2486         const char *op = is_accept ? "accept" : "connect";
2487
2488         if ( pem_module ) {
2489                 LDAP_MUTEX_LOCK( &tlsm_pem_mutex );
2490         }
2491         rc = SSL_ForceHandshake( s );
2492         if ( pem_module ) {
2493                 LDAP_MUTEX_UNLOCK( &tlsm_pem_mutex );
2494         }
2495         if ( rc ) {
2496                 PRErrorCode err = PR_GetError();
2497                 rc = -1;
2498                 if ( err == PR_WOULD_BLOCK_ERROR ) {
2499                         ber_tag_t thetag = LBER_DEFAULT;
2500                         /* see if we are blocked because of a bogus packet */
2501                         if ( tlsm_is_non_ssl_message( s, &thetag ) ) { /* see if we received a non-SSL message */
2502                                 Debug( LDAP_DEBUG_ANY, 
2503                                            "TLS: error: %s - error - received non-SSL message [0x%x]\n",
2504                                            op, (unsigned int)thetag, 0 );
2505                                 /* reset error to something more descriptive */
2506                                 PR_SetError( SSL_ERROR_RX_MALFORMED_HELLO_REQUEST, EPROTO );
2507                         }
2508                 } else {
2509                         Debug( LDAP_DEBUG_ANY, 
2510                                    "TLS: error: %s - force handshake failure: errno %d - moznss error %d\n",
2511                                    op, errno, err );
2512                 }
2513         }
2514
2515         return rc;
2516 }
2517 static int
2518 tlsm_session_accept( tls_session *session )
2519 {
2520         return tlsm_session_accept_or_connect( session, 1 );
2521 }
2522
2523 static int
2524 tlsm_session_connect( LDAP *ld, tls_session *session )
2525 {
2526         return tlsm_session_accept_or_connect( session, 0 );
2527 }
2528
2529 static int
2530 tlsm_session_upflags( Sockbuf *sb, tls_session *session, int rc )
2531 {
2532         int prerror = PR_GetError();
2533
2534         if ( ( prerror == PR_PENDING_INTERRUPT_ERROR ) || ( prerror == PR_WOULD_BLOCK_ERROR ) ) {
2535                 tlsm_session *s = (tlsm_session *)session;
2536                 struct tls_data *p = tlsm_get_pvt_tls_data( s );
2537
2538                 if ( p && ( p->io_flag == TLSM_READ ) ) {
2539                         sb->sb_trans_needs_read = 1;
2540                         return 1;
2541                 } else if ( p && ( p->io_flag == TLSM_WRITE ) ) {
2542                         sb->sb_trans_needs_write = 1;
2543                         return 1;
2544                 }
2545         }
2546
2547         return 0;
2548 }
2549
2550 static char *
2551 tlsm_session_errmsg( tls_session *sess, int rc, char *buf, size_t len )
2552 {
2553         int i;
2554         int prerror = PR_GetError();
2555
2556         i = PR_GetErrorTextLength();
2557         if ( i > len ) {
2558                 char *msg = LDAP_MALLOC( i+1 );
2559                 PR_GetErrorText( msg );
2560                 memcpy( buf, msg, len );
2561                 LDAP_FREE( msg );
2562         } else if ( i ) {
2563                 PR_GetErrorText( buf );
2564         } else if ( prerror ) {
2565                 i = PR_snprintf( buf, len, "TLS error %d:%s",
2566                                                  prerror, PR_ErrorToString( prerror, PR_LANGUAGE_I_DEFAULT ) );
2567         }
2568
2569         return ( i > 0 ) ? buf : NULL;
2570 }
2571
2572 static int
2573 tlsm_session_my_dn( tls_session *session, struct berval *der_dn )
2574 {
2575         tlsm_session *s = (tlsm_session *)session;
2576         CERTCertificate *cert;
2577
2578         cert = SSL_LocalCertificate( s );
2579         if (!cert) return LDAP_INVALID_CREDENTIALS;
2580
2581         der_dn->bv_val = (char *)cert->derSubject.data;
2582         der_dn->bv_len = cert->derSubject.len;
2583         CERT_DestroyCertificate( cert );
2584         return 0;
2585 }
2586
2587 static int
2588 tlsm_session_peer_dn( tls_session *session, struct berval *der_dn )
2589 {
2590         tlsm_session *s = (tlsm_session *)session;
2591         CERTCertificate *cert;
2592
2593         cert = SSL_PeerCertificate( s );
2594         if (!cert) return LDAP_INVALID_CREDENTIALS;
2595         
2596         der_dn->bv_val = (char *)cert->derSubject.data;
2597         der_dn->bv_len = cert->derSubject.len;
2598         CERT_DestroyCertificate( cert );
2599         return 0;
2600 }
2601
2602 /* what kind of hostname were we given? */
2603 #define IS_DNS  0
2604 #define IS_IP4  1
2605 #define IS_IP6  2
2606
2607 static int
2608 tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
2609 {
2610         tlsm_session *s = (tlsm_session *)session;
2611         CERTCertificate *cert;
2612         const char *name, *domain = NULL, *ptr;
2613         int ret, ntype = IS_DNS, nlen, dlen;
2614 #ifdef LDAP_PF_INET6
2615         struct in6_addr addr;
2616 #else
2617         struct in_addr addr;
2618 #endif
2619         SECItem altname;
2620         SECStatus rv;
2621
2622         if( ldap_int_hostname &&
2623                 ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
2624         {
2625                 name = ldap_int_hostname;
2626         } else {
2627                 name = name_in;
2628         }
2629         nlen = strlen( name );
2630
2631         cert = SSL_PeerCertificate( s );
2632         if (!cert) {
2633                 Debug( LDAP_DEBUG_ANY,
2634                         "TLS: unable to get peer certificate.\n",
2635                         0, 0, 0 );
2636                 /* if this was a fatal condition, things would have
2637                  * aborted long before now.
2638                  */
2639                 return LDAP_SUCCESS;
2640         }
2641
2642 #ifdef LDAP_PF_INET6
2643         if (inet_pton(AF_INET6, name, &addr)) {
2644                 ntype = IS_IP6;
2645         } else 
2646 #endif
2647         if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
2648                 if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
2649         }
2650         if (ntype == IS_DNS ) {
2651                 domain = strchr( name, '.' );
2652                 if ( domain )
2653                         dlen = nlen - ( domain - name );
2654         }
2655
2656         ret = LDAP_LOCAL_ERROR;
2657
2658         rv = CERT_FindCertExtension( cert, SEC_OID_X509_SUBJECT_ALT_NAME,
2659                 &altname );
2660         if ( rv == SECSuccess && altname.data ) {
2661                 PRArenaPool *arena;
2662                 CERTGeneralName *names, *cur;
2663
2664                 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2665                 if ( !arena ) {
2666                         ret = LDAP_NO_MEMORY;
2667                         goto fail;
2668                 }
2669
2670                 names = cur = CERT_DecodeAltNameExtension(arena, &altname);
2671                 if ( !cur )
2672                         goto altfail;
2673
2674                 do {
2675                         char *host;
2676                         int hlen;
2677
2678                         /* ignore empty */
2679                         if ( !cur->name.other.len ) continue;
2680
2681                         host = (char *)cur->name.other.data;
2682                         hlen = cur->name.other.len;
2683
2684                         if ( cur->type == certDNSName ) {
2685                                 if ( ntype != IS_DNS )  continue;
2686
2687                                 /* is this an exact match? */
2688                                 if ( nlen == hlen && !strncasecmp( name, host, nlen )) {
2689                                         ret = LDAP_SUCCESS;
2690                                         break;
2691                                 }
2692
2693                                 /* is this a wildcard match? */
2694                                 if ( domain && host[0] == '*' && host[1] == '.' &&
2695                                         dlen == hlen-1 && !strncasecmp( domain, host+1, dlen )) {
2696                                         ret = LDAP_SUCCESS;
2697                                         break;
2698                                 }
2699                         } else if ( cur->type == certIPAddress ) {
2700                                 if ( ntype == IS_DNS )  continue;
2701                                 
2702 #ifdef LDAP_PF_INET6
2703                                 if (ntype == IS_IP6 && hlen != sizeof(struct in6_addr)) {
2704                                         continue;
2705                                 } else
2706 #endif
2707                                 if (ntype == IS_IP4 && hlen != sizeof(struct in_addr)) {
2708                                         continue;
2709                                 }
2710                                 if (!memcmp(host, &addr, hlen)) {
2711                                         ret = LDAP_SUCCESS;
2712                                         break;
2713                                 }
2714                         }
2715                 } while (( cur = CERT_GetNextGeneralName( cur )) != names );
2716 altfail:
2717                 PORT_FreeArena( arena, PR_FALSE );
2718                 SECITEM_FreeItem( &altname, PR_FALSE );
2719         }
2720         /* no altnames matched, try the CN */
2721         if ( ret != LDAP_SUCCESS ) {
2722                 /* find the last CN */
2723                 CERTRDN *rdn, **rdns;
2724                 CERTAVA *lastava = NULL;
2725                 char buf[2048];
2726
2727                 buf[0] = '\0';
2728                 rdns = cert->subject.rdns;
2729                 while ( rdns && ( rdn = *rdns++ )) {
2730                         CERTAVA *ava, **avas = rdn->avas;
2731                         while ( avas && ( ava = *avas++ )) {
2732                                 if ( CERT_GetAVATag( ava ) == SEC_OID_AVA_COMMON_NAME )
2733                                         lastava = ava;
2734                         }
2735                 }
2736                 if ( lastava ) {
2737                         SECItem *av = CERT_DecodeAVAValue( &lastava->value );
2738                         if ( av ) {
2739                                 if ( av->len == nlen && !strncasecmp( name, (char *)av->data, nlen )) {
2740                                         ret = LDAP_SUCCESS;
2741                                 } else if ( av->data[0] == '*' && av->data[1] == '.' &&
2742                                         domain && dlen == av->len - 1 && !strncasecmp( domain,
2743                                                 (char *)(av->data+1), dlen )) {
2744                                         ret = LDAP_SUCCESS;
2745                                 } else {
2746                                         int len = av->len;
2747                                         if ( len >= sizeof(buf) )
2748                                                 len = sizeof(buf)-1;
2749                                         memcpy( buf, av->data, len );
2750                                         buf[len] = '\0';
2751                                 }
2752                                 SECITEM_FreeItem( av, PR_TRUE );
2753                         }
2754                 }
2755                 if ( ret != LDAP_SUCCESS ) {
2756                         Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
2757                                 "common name in certificate (%s).\n", 
2758                                 name, buf, 0 );
2759                         ret = LDAP_CONNECT_ERROR;
2760                         if ( ld->ld_error ) {
2761                                 LDAP_FREE( ld->ld_error );
2762                         }
2763                         ld->ld_error = LDAP_STRDUP(
2764                                 _("TLS: hostname does not match CN in peer certificate"));
2765                 }
2766         }
2767
2768 fail:
2769         CERT_DestroyCertificate( cert );
2770         return ret;
2771 }
2772
2773 static int
2774 tlsm_session_strength( tls_session *session )
2775 {
2776         tlsm_session *s = (tlsm_session *)session;
2777         int rc, keySize;
2778
2779         rc = SSL_SecurityStatus( s, NULL, NULL, NULL, &keySize,
2780                 NULL, NULL );
2781         return rc ? 0 : keySize;
2782 }
2783
2784 /*
2785  * TLS support for LBER Sockbufs
2786  */
2787
2788 static PRStatus PR_CALLBACK
2789 tlsm_PR_Close(PRFileDesc *fd)
2790 {
2791         int rc = PR_SUCCESS;
2792
2793         /* we don't need to actually close anything here, just
2794            pop our io layer off the stack */
2795         fd->secret = NULL; /* must have been freed before calling PR_Close */
2796         if ( fd->lower ) {
2797                 fd = PR_PopIOLayer( fd, tlsm_layer_id );
2798                 /* if we are not the last layer, pass the close along */
2799                 if ( fd ) {
2800                         if ( fd->dtor ) {
2801                                 fd->dtor( fd );
2802                         }
2803                         rc = fd->methods->close( fd );
2804                 }
2805         } else {
2806                 /* we are the last layer - just call our dtor */
2807                 fd->dtor(fd);
2808         }
2809
2810         return rc;
2811 }
2812
2813 static PRStatus PR_CALLBACK
2814 tlsm_PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
2815 {
2816         int rc = PR_SUCCESS;
2817
2818         if ( fd->lower ) {
2819                 rc = PR_Shutdown( fd->lower, how );
2820         }
2821
2822         return rc;
2823 }
2824
2825 static int PR_CALLBACK
2826 tlsm_PR_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags,
2827          PRIntervalTime timeout)
2828 {
2829         struct tls_data         *p;
2830         int rc;
2831
2832         if ( buf == NULL || len <= 0 ) return 0;
2833
2834         p = tlsm_get_pvt_tls_data( fd );
2835
2836         if ( p == NULL || p->sbiod == NULL ) {
2837                 return 0;
2838         }
2839
2840         rc = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
2841         if (rc <= 0) {
2842                 tlsm_map_error( errno );
2843                 if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
2844                         p->nonblock = PR_TRUE; /* fd is using non-blocking io */
2845                 } else if ( errno ) { /* real error */
2846                         Debug( LDAP_DEBUG_TRACE, 
2847                                "TLS: error: tlsm_PR_Recv returned %d - error %d:%s\n",
2848                                rc, errno, STRERROR(errno) );
2849                 }
2850         } else if ( ( rc > 0 ) && ( len > 0 ) && ( p->firsttag == LBER_DEFAULT ) ) {
2851                 p->firsttag = (ber_tag_t)*((char *)buf);
2852         }
2853         p->io_flag = TLSM_READ;
2854
2855         return rc;
2856 }
2857
2858 static int PR_CALLBACK
2859 tlsm_PR_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags,
2860          PRIntervalTime timeout)
2861 {
2862         struct tls_data         *p;
2863         int rc;
2864
2865         if ( buf == NULL || len <= 0 ) return 0;
2866
2867         p = tlsm_get_pvt_tls_data( fd );
2868
2869         if ( p == NULL || p->sbiod == NULL ) {
2870                 return 0;
2871         }
2872
2873         rc = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
2874         if (rc <= 0) {
2875                 tlsm_map_error( errno );
2876                 if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
2877                         p->nonblock = PR_TRUE;
2878                 } else if ( errno ) { /* real error */
2879                         Debug( LDAP_DEBUG_TRACE, 
2880                                "TLS: error: tlsm_PR_Send returned %d - error %d:%s\n",
2881                                rc, errno, STRERROR(errno) );
2882                 }
2883         }
2884         p->io_flag = TLSM_WRITE;
2885
2886         return rc;
2887 }
2888
2889 static int PR_CALLBACK
2890 tlsm_PR_Read(PRFileDesc *fd, void *buf, PRInt32 len)
2891 {
2892         return tlsm_PR_Recv( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
2893 }
2894
2895 static int PR_CALLBACK
2896 tlsm_PR_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
2897 {
2898         return tlsm_PR_Send( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
2899 }
2900
2901 static PRStatus PR_CALLBACK
2902 tlsm_PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
2903 {
2904         struct tls_data         *p;
2905         ber_socklen_t len;
2906
2907         p = tlsm_get_pvt_tls_data( fd );
2908
2909         if ( p == NULL || p->sbiod == NULL ) {
2910                 return PR_FAILURE;
2911         }
2912         len = sizeof(PRNetAddr);
2913         return getpeername( p->sbiod->sbiod_sb->sb_fd, (struct sockaddr *)addr, &len );
2914 }
2915
2916 static PRStatus PR_CALLBACK
2917 tlsm_PR_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
2918 {
2919         struct tls_data         *p;
2920         p = tlsm_get_pvt_tls_data( fd );
2921
2922         if ( p == NULL || data == NULL ) {
2923                 return PR_FAILURE;
2924         }
2925
2926         /* only the nonblocking option is supported at this time
2927            MozNSS SSL code needs it */
2928         if ( data->option != PR_SockOpt_Nonblocking ) {
2929                 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2930                 return PR_FAILURE;
2931         }
2932 #ifdef HAVE_FCNTL
2933         int flags = fcntl( p->sbiod->sbiod_sb->sb_fd, F_GETFL );
2934         data->value.non_blocking = (flags & O_NONBLOCK) ? PR_TRUE : PR_FALSE;           
2935 #else /* punt :P */
2936         data->value.non_blocking = p->nonblock;
2937 #endif
2938         return PR_SUCCESS;
2939 }
2940
2941 static PRStatus PR_CALLBACK
2942 tlsm_PR_prs_unimp()
2943 {
2944     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2945     return PR_FAILURE;
2946 }
2947
2948 static PRFileDesc * PR_CALLBACK
2949 tlsm_PR_pfd_unimp()
2950 {
2951     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2952     return NULL;
2953 }
2954
2955 static PRInt16 PR_CALLBACK
2956 tlsm_PR_i16_unimp()
2957 {
2958     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2959     return SECFailure;
2960 }
2961
2962 static PRInt32 PR_CALLBACK
2963 tlsm_PR_i32_unimp()
2964 {
2965     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2966     return SECFailure;
2967 }
2968
2969 static PRInt64 PR_CALLBACK
2970 tlsm_PR_i64_unimp()
2971 {
2972     PRInt64 res;
2973
2974     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2975     LL_I2L(res, -1L);
2976     return res;
2977 }
2978
2979 static const PRIOMethods tlsm_PR_methods = {
2980     PR_DESC_LAYERED,
2981     tlsm_PR_Close,                      /* close        */
2982     tlsm_PR_Read,                       /* read         */
2983     tlsm_PR_Write,                      /* write        */
2984     tlsm_PR_i32_unimp,          /* available    */
2985     tlsm_PR_i64_unimp,          /* available64  */
2986     tlsm_PR_prs_unimp,          /* fsync        */
2987     tlsm_PR_i32_unimp,          /* seek         */
2988     tlsm_PR_i64_unimp,          /* seek64       */
2989     tlsm_PR_prs_unimp,          /* fileInfo     */
2990     tlsm_PR_prs_unimp,          /* fileInfo64   */
2991     tlsm_PR_i32_unimp,          /* writev       */
2992     tlsm_PR_prs_unimp,          /* connect      */
2993     tlsm_PR_pfd_unimp,          /* accept       */
2994     tlsm_PR_prs_unimp,          /* bind         */
2995     tlsm_PR_prs_unimp,          /* listen       */
2996     (PRShutdownFN)tlsm_PR_Shutdown,                     /* shutdown     */
2997     tlsm_PR_Recv,                       /* recv         */
2998     tlsm_PR_Send,                       /* send         */
2999     tlsm_PR_i32_unimp,          /* recvfrom     */
3000     tlsm_PR_i32_unimp,          /* sendto       */
3001     (PRPollFN)tlsm_PR_i16_unimp,        /* poll         */
3002     tlsm_PR_i32_unimp,          /* acceptread   */
3003     tlsm_PR_i32_unimp,          /* transmitfile */
3004     tlsm_PR_prs_unimp,          /* getsockname  */
3005     tlsm_PR_GetPeerName,        /* getpeername  */
3006     tlsm_PR_i32_unimp,          /* getsockopt   OBSOLETE */
3007     tlsm_PR_i32_unimp,          /* setsockopt   OBSOLETE */
3008     tlsm_PR_GetSocketOption,            /* getsocketoption   */
3009     tlsm_PR_i32_unimp,          /* setsocketoption   */
3010     tlsm_PR_i32_unimp,          /* Send a (partial) file with header/trailer*/
3011     (PRConnectcontinueFN)tlsm_PR_prs_unimp,             /* connectcontinue */
3012     tlsm_PR_i32_unimp,          /* reserved for future use */
3013     tlsm_PR_i32_unimp,          /* reserved for future use */
3014     tlsm_PR_i32_unimp,          /* reserved for future use */
3015     tlsm_PR_i32_unimp           /* reserved for future use */
3016 };
3017
3018 /*
3019  * Initialize TLS subsystem. Should be called only once.
3020  * See tlsm_deferred_init for the bulk of the init process
3021  */
3022 static int
3023 tlsm_init( void )
3024 {
3025         char *nofork = PR_GetEnv( "NSS_STRICT_NOFORK" );
3026
3027         PR_Init(0, 0, 0);
3028
3029         tlsm_layer_id = PR_GetUniqueIdentity( "OpenLDAP" );
3030
3031         /*
3032          * There are some applications that acquire a crypto context in the parent process
3033          * and expect that crypto context to work after a fork().  This does not work
3034          * with NSS using strict PKCS11 compliance mode.  We set this environment
3035          * variable here to tell the software encryption module/token to allow crypto
3036          * contexts to persist across a fork().  However, if you are using some other
3037          * module or encryption device that supports and expects full PKCS11 semantics,
3038          * the only recourse is to rewrite the application with atfork() handlers to save
3039          * the crypto context in the parent and restore (and SECMOD_RestartModules) the
3040          * context in the child.
3041          */
3042         if ( !nofork ) {
3043                 /* will leak one time */
3044                 char *noforkenvvar = PL_strdup( "NSS_STRICT_NOFORK=DISABLED" );
3045                 PR_SetEnv( noforkenvvar );
3046         }
3047
3048         return 0;
3049 }
3050
3051 static int
3052 tlsm_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
3053 {
3054         struct tls_data         *p;
3055         tlsm_session    *session = arg;
3056         PRFileDesc *fd;
3057
3058         assert( sbiod != NULL );
3059
3060         p = LBER_MALLOC( sizeof( *p ) );
3061         if ( p == NULL ) {
3062                 return -1;
3063         }
3064
3065         fd = PR_GetIdentitiesLayer( session, tlsm_layer_id );
3066         if ( !fd ) {
3067                 LBER_FREE( p );
3068                 return -1;
3069         }
3070
3071         fd->secret = (PRFilePrivate *)p;
3072         p->session = session;
3073         p->sbiod = sbiod;
3074         p->firsttag = LBER_DEFAULT;
3075         sbiod->sbiod_pvt = p;
3076         return 0;
3077 }
3078
3079 static int
3080 tlsm_sb_remove( Sockbuf_IO_Desc *sbiod )
3081 {
3082         struct tls_data         *p;
3083         
3084         assert( sbiod != NULL );
3085         assert( sbiod->sbiod_pvt != NULL );
3086
3087         p = (struct tls_data *)sbiod->sbiod_pvt;
3088         PR_Close( p->session );
3089         LBER_FREE( sbiod->sbiod_pvt );
3090         sbiod->sbiod_pvt = NULL;
3091         return 0;
3092 }
3093
3094 static int
3095 tlsm_sb_close( Sockbuf_IO_Desc *sbiod )
3096 {
3097         struct tls_data         *p;
3098         
3099         assert( sbiod != NULL );
3100         assert( sbiod->sbiod_pvt != NULL );
3101
3102         p = (struct tls_data *)sbiod->sbiod_pvt;
3103         PR_Shutdown( p->session, PR_SHUTDOWN_BOTH );
3104         return 0;
3105 }
3106
3107 static int
3108 tlsm_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
3109 {
3110         struct tls_data         *p;
3111         
3112         assert( sbiod != NULL );
3113         assert( sbiod->sbiod_pvt != NULL );
3114
3115         p = (struct tls_data *)sbiod->sbiod_pvt;
3116         
3117         if ( opt == LBER_SB_OPT_GET_SSL ) {
3118                 *((tlsm_session **)arg) = p->session;
3119                 return 1;
3120                 
3121         } else if ( opt == LBER_SB_OPT_DATA_READY ) {
3122                 if ( p && ( SSL_DataPending( p->session ) > 0 ) ) {
3123                         return 1;
3124                 }
3125                 
3126         }
3127         
3128         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
3129 }
3130
3131 static ber_slen_t
3132 tlsm_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
3133 {
3134         struct tls_data         *p;
3135         ber_slen_t              ret;
3136         int                     err;
3137
3138         assert( sbiod != NULL );
3139         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
3140
3141         p = (struct tls_data *)sbiod->sbiod_pvt;
3142
3143         ret = PR_Recv( p->session, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
3144         if ( ret < 0 ) {
3145                 err = PR_GetError();
3146                 if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
3147                         sbiod->sbiod_sb->sb_trans_needs_read = 1;
3148                         sock_errset(EWOULDBLOCK);
3149                 }
3150         } else {
3151                 sbiod->sbiod_sb->sb_trans_needs_read = 0;
3152         }
3153         return ret;
3154 }
3155
3156 static ber_slen_t
3157 tlsm_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
3158 {
3159         struct tls_data         *p;
3160         ber_slen_t              ret;
3161         int                     err;
3162
3163         assert( sbiod != NULL );
3164         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
3165
3166         p = (struct tls_data *)sbiod->sbiod_pvt;
3167
3168         ret = PR_Send( p->session, (char *)buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
3169         if ( ret < 0 ) {
3170                 err = PR_GetError();
3171                 if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
3172                         sbiod->sbiod_sb->sb_trans_needs_write = 1;
3173                         sock_errset(EWOULDBLOCK);
3174                         ret = 0;
3175                 }
3176         } else {
3177                 sbiod->sbiod_sb->sb_trans_needs_write = 0;
3178         }
3179         return ret;
3180 }
3181
3182 static Sockbuf_IO tlsm_sbio =
3183 {
3184         tlsm_sb_setup,          /* sbi_setup */
3185         tlsm_sb_remove,         /* sbi_remove */
3186         tlsm_sb_ctrl,           /* sbi_ctrl */
3187         tlsm_sb_read,           /* sbi_read */
3188         tlsm_sb_write,          /* sbi_write */
3189         tlsm_sb_close           /* sbi_close */
3190 };
3191
3192 tls_impl ldap_int_tls_impl = {
3193         "MozNSS",
3194
3195         tlsm_init,
3196         tlsm_destroy,
3197
3198         tlsm_ctx_new,
3199         tlsm_ctx_ref,
3200         tlsm_ctx_free,
3201         tlsm_ctx_init,
3202
3203         tlsm_session_new,
3204         tlsm_session_connect,
3205         tlsm_session_accept,
3206         tlsm_session_upflags,
3207         tlsm_session_errmsg,
3208         tlsm_session_my_dn,
3209         tlsm_session_peer_dn,
3210         tlsm_session_chkhost,
3211         tlsm_session_strength,
3212
3213         &tlsm_sbio,
3214
3215 #ifdef LDAP_R_COMPILE
3216         tlsm_thr_init,
3217 #else
3218         NULL,
3219 #endif
3220
3221         0
3222 };
3223
3224 #endif /* HAVE_MOZNSS */
3225 /*
3226   emacs settings
3227   Local Variables:
3228   indent-tabs-mode: t
3229   tab-width: 4
3230   End:
3231 */