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