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