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