]> git.sur5r.net Git - openldap/blob - libraries/libldap/gnutls.c
Add LDAP_OPT_X_TLS_CRLFILE, peer cert verification for GNUtls
[openldap] / libraries / libldap / gnutls.c
1 /* gnutls.c - Handle tls/ssl using GNUTLS. */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2007 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:
17  */
18
19 #include "portable.h"
20
21 #define HAVE_GNUTLS     1
22 #ifdef HAVE_GNUTLS
23
24 #include "ldap_config.h"
25
26 #include <stdio.h>
27
28 #include <ac/stdlib.h>
29 #include <ac/errno.h>
30 #include <ac/socket.h>
31 #include <ac/string.h>
32 #include <ac/ctype.h>
33 #include <ac/time.h>
34 #include <ac/unistd.h>
35 #include <ac/param.h>
36 #include <ac/dirent.h>
37
38 #include "ldap-int.h"
39 #include "ldap_schema.h"
40
41 #include <gnutls/gnutls.h>
42 #include <gnutls/x509.h>
43 #include <gcrypt.h>
44
45 #define DH_BITS (1024)
46
47 #ifdef LDAP_R_COMPILE
48 #  include <ldap_pvt_thread.h>
49
50 static int
51 ldap_pvt_gcry_mutex_init( void **priv )
52 {
53         int err = 0;
54         ldap_pvt_thread_mutex_t *lock = LDAP_MALLOC( sizeof( ldap_pvt_thread_mutex_t ));
55
56         if ( !lock )
57                 err = ENOMEM;
58         if ( !err ) {
59                 err = ldap_pvt_thread_mutex_init( lock );
60                 if ( err )
61                         LDAP_FREE( lock );
62                 else
63                         *priv = lock;
64         }
65         return err;
66 }
67 static int
68 ldap_pvt_gcry_mutex_destroy( void **lock )
69 {
70         int err = ldap_pvt_thread_mutex_destroy( *lock );
71         LDAP_FREE( *lock );
72         return err;
73 }
74 static int
75 ldap_pvt_gcry_mutex_lock( void **lock )
76 {
77         return ldap_pvt_thread_mutex_lock( *lock );
78 }
79 static int
80 ldap_pvt_gcry_mutex_unlock( void **lock )
81 {
82         return ldap_pvt_thread_mutex_unlock( *lock );
83 }
84
85 static struct gcry_thread_cbs ldap_generic_thread_cbs = {
86         GCRY_THREAD_OPTION_USER,
87         NULL,
88         ldap_pvt_gcry_mutex_init,
89         ldap_pvt_gcry_mutex_destroy,
90         ldap_pvt_gcry_mutex_lock,
91         ldap_pvt_gcry_mutex_unlock,
92         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
93 };
94 #endif
95
96 /* sorta replacing SSL_CTX */
97 typedef struct ldap_pvt_tls_ctx {
98         struct ldapoptions *lo;
99         int *cipher_list;
100         gnutls_certificate_credentials_t cred;
101         gnutls_dh_params_t dh_params;
102         unsigned long verify_depth;
103         int refcount;
104 #ifdef LDAP_R_COMPILE
105         ldap_pvt_thread_mutex_t ref_mutex;
106 #endif
107 } ldap_pvt_tls_ctx_t;
108
109 /* sorta replacing SSL */
110 typedef struct ldap_pvt_gnutls_session {
111         ldap_pvt_tls_ctx_t *ctx;
112         gnutls_session_t session;
113         struct berval peer_der_dn;
114 } ldap_pvt_gnutls_session_t;
115
116 #define HAS_TLS( sb )   ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \
117                                 (void *)&sb_tls_sbio )
118
119 /* RFC2459 minimum required set of supported attribute types
120  */
121 typedef struct oid_name {
122         struct berval oid;
123         struct berval name;
124 } oid_name;
125
126 #define CN_OID  oids[0].oid.bv_val
127
128 static oid_name oids[] = {
129         { BER_BVC("2.5.4.3"), BER_BVC("cn") },
130         { BER_BVC("2.5.4.4"), BER_BVC("sn") },
131         { BER_BVC("2.5.4.6"), BER_BVC("c") },
132         { BER_BVC("2.5.4.7"), BER_BVC("l") },
133         { BER_BVC("2.5.4.8"), BER_BVC("st") },
134         { BER_BVC("2.5.4.10"), BER_BVC("o") },
135         { BER_BVC("2.5.4.11"), BER_BVC("ou") },
136         { BER_BVC("2.5.4.12"), BER_BVC("title") },
137         { BER_BVC("2.5.4.41"), BER_BVC("name") },
138         { BER_BVC("2.5.4.42"), BER_BVC("givenName") },
139         { BER_BVC("2.5.4.43"), BER_BVC("initials") },
140         { BER_BVC("2.5.4.44"), BER_BVC("generationQualifier") },
141         { BER_BVC("2.5.4.46"), BER_BVC("dnQualifier") },
142         { BER_BVC("1.2.840.113549.1.9.1"), BER_BVC("email") },
143         { BER_BVC("0.9.2342.19200300.100.1.25"), BER_BVC("dc") },
144         { BER_BVNULL, BER_BVNULL }
145 };
146
147 ldap_pvt_tls_ctx_t *
148 ldap_pvt_tls_ctx_new ( struct ldapoptions *lo )
149 {
150         ldap_pvt_tls_ctx_t *ctx;
151
152         ctx = ber_memcalloc ( 1, sizeof (*ctx) );
153         if ( ctx ) {
154                 ctx->lo = lo;
155                 if ( gnutls_certificate_allocate_credentials( &ctx->cred ) < 0 ) {
156                         ber_memfree( ctx );
157                         return NULL;
158                 }
159                 ctx->refcount = 1;
160 #ifdef LDAP_R_COMPILE
161                 ldap_pvt_thread_mutex_init( &ctx->ref_mutex );
162 #endif
163         }
164         return ctx;
165 }
166
167 void
168 ldap_pvt_tls_ctx_free ( void *c )
169 {
170         int refcount;
171         ldap_pvt_tls_ctx_t *ctx = c;
172
173 #ifdef LDAP_R_COMPILE
174         ldap_pvt_thread_mutex_lock( &ctx->ref_mutex );
175 #endif
176         refcount = --ctx->refcount;
177 #ifdef LDAP_R_COMPILE
178         ldap_pvt_thread_mutex_unlock( &ctx->ref_mutex );
179 #endif
180         if ( refcount )
181                 return;
182         gnutls_certificate_free_credentials( ctx->cred );
183         ber_memfree ( ctx );
184 }
185
186 static void
187 ldap_pvt_tls_ctx_ref( ldap_pvt_tls_ctx_t * ctx )
188 {
189 #ifdef LDAP_R_COMPILE
190         ldap_pvt_thread_mutex_lock( &ctx->ref_mutex );
191 #endif
192         ctx->refcount++;
193 #ifdef LDAP_R_COMPILE
194         ldap_pvt_thread_mutex_unlock( &ctx->ref_mutex );
195 #endif
196 }
197
198 ldap_pvt_gnutls_session_t *
199 ldap_pvt_gnutls_session_new ( ldap_pvt_tls_ctx_t * ctx, int is_server )
200 {
201         ldap_pvt_gnutls_session_t *session;
202
203         session = ber_memcalloc ( 1, sizeof (*session) );
204         if ( !session )
205                 return NULL;
206
207         gnutls_init( &session->session, is_server ? GNUTLS_SERVER : GNUTLS_CLIENT );
208         gnutls_set_default_priority( session->session );
209         if ( ctx->cred )
210                 gnutls_credentials_set( session->session, GNUTLS_CRD_CERTIFICATE, ctx->cred );
211         
212         if ( is_server ) {
213                 int flag = 0;
214                 if ( ctx->lo->ldo_tls_require_cert ) {
215                         flag = GNUTLS_CERT_REQUEST;
216                         if ( ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND ||
217                                 ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD )
218                                 flag = GNUTLS_CERT_REQUIRE;
219                         gnutls_certificate_server_set_request( session->session, flag );
220                 }
221         }
222         return session;
223
224
225 void
226 ldap_pvt_gnutls_session_free ( ldap_pvt_gnutls_session_t * session )
227 {
228         ber_memfree ( session );
229 }
230
231 #ifdef LDAP_R_COMPILE
232 static void
233 tls_init_threads( void )
234 {
235         gcry_control (GCRYCTL_SET_THREAD_CBS, &ldap_generic_thread_cbs);
236 }
237 #endif
238
239 void
240 ldap_int_tls_destroy( struct ldapoptions *lo )
241 {
242         if ( lo->ldo_tls_ctx ) {
243                 ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
244                 lo->ldo_tls_ctx = NULL;
245         }
246
247         if ( lo->ldo_tls_certfile ) {
248                 LDAP_FREE( lo->ldo_tls_certfile );
249                 lo->ldo_tls_certfile = NULL;
250         }
251         if ( lo->ldo_tls_keyfile ) {
252                 LDAP_FREE( lo->ldo_tls_keyfile );
253                 lo->ldo_tls_keyfile = NULL;
254         }
255         if ( lo->ldo_tls_dhfile ) {
256                 LDAP_FREE( lo->ldo_tls_dhfile );
257                 lo->ldo_tls_dhfile = NULL;
258         }
259         if ( lo->ldo_tls_cacertfile ) {
260                 LDAP_FREE( lo->ldo_tls_cacertfile );
261                 lo->ldo_tls_cacertfile = NULL;
262         }
263         if ( lo->ldo_tls_cacertdir ) {
264                 LDAP_FREE( lo->ldo_tls_cacertdir );
265                 lo->ldo_tls_cacertdir = NULL;
266         }
267         if ( lo->ldo_tls_ciphersuite ) {
268                 LDAP_FREE( lo->ldo_tls_ciphersuite );
269                 lo->ldo_tls_ciphersuite = NULL;
270         }
271 }
272
273 /*
274  * Tear down the TLS subsystem. Should only be called once.
275  */
276 void
277 ldap_pvt_tls_destroy( void )
278 {
279         struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();
280
281         ldap_int_tls_destroy( lo );
282
283         gnutls_global_deinit();
284 }
285
286 /*
287  * Initialize TLS subsystem. Should be called only once.
288  */
289 int
290 ldap_pvt_tls_init( void )
291 {
292         static int tls_initialized = 0;
293
294         if ( tls_initialized++ ) return 0;
295
296 #ifdef LDAP_R_COMPILE
297         tls_init_threads();
298 #endif
299         gnutls_global_init ();
300         return 0;
301 }
302
303 /*
304  * initialize a new TLS context
305  */
306 static int
307 ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server )
308 {
309         int i, rc = 0;
310         char *ciphersuite = lo->ldo_tls_ciphersuite;
311         char *cacertfile = lo->ldo_tls_cacertfile;
312         char *cacertdir = lo->ldo_tls_cacertdir;
313         char *certfile = lo->ldo_tls_certfile;
314         char *keyfile = lo->ldo_tls_keyfile;
315         char *dhfile = lo->ldo_tls_dhfile;
316         char *crlfile = lo->ldo_tls_crlfile;
317
318         if ( lo->ldo_tls_ctx )
319                 return 0;
320
321         ldap_pvt_tls_init();
322
323         if ( is_server && !certfile && !keyfile && !cacertfile && !cacertdir ) {
324                 /* minimum configuration not provided */
325                 return LDAP_NOT_SUPPORTED;
326         }
327
328 #ifdef HAVE_EBCDIC
329         /* This ASCII/EBCDIC handling is a real pain! */
330         if ( ciphersuite ) {
331                 ciphersuite = LDAP_STRDUP( ciphersuite );
332                 __atoe( ciphersuite );
333         }
334         if ( cacertfile ) {
335                 cacertfile = LDAP_STRDUP( cacertfile );
336                 __atoe( cacertfile );
337         }
338         if ( cacertdir ) {
339                 cacertdir = LDAP_STRDUP( cacertdir );
340                 __atoe( cacertdir );
341         }
342         if ( certfile ) {
343                 certfile = LDAP_STRDUP( certfile );
344                 __atoe( certfile );
345         }
346         if ( keyfile ) {
347                 keyfile = LDAP_STRDUP( keyfile );
348                 __atoe( keyfile );
349         }
350         if ( dhfile ) {
351                 dhfile = LDAP_STRDUP( dhfile );
352                 __atoe( dhfile );
353         }
354         if ( crlfile ) {
355                 crlfile = LDAP_STRDUP( crlfile );
356                 __atoe( crlfile );
357         }
358 #endif
359         lo->ldo_tls_ctx = ldap_pvt_tls_ctx_new ( lo );
360         if ( lo->ldo_tls_ctx == NULL ) {
361                 Debug( LDAP_DEBUG_ANY,
362                        "TLS: could not allocate default ctx.\n",
363                        0,0,0);
364                 rc = -1;
365                 goto error_exit;
366         }
367
368         /* fixme convert ciphersuite spec formats? */
369 /*      if ( lo->ldo_tls_ciphersuite && hm ) { */
370 /*              Debug( LDAP_DEBUG_ANY, */
371 /*                         "TLS: could not set cipher list %s.\n", */
372 /*                         lo->ldo_tls_ciphersuite, 0, 0 ); */
373 /*              tls_report_error(); */
374 /*              rc = -1; */
375 /*              goto error_exit; */
376 /*      } */
377
378         if (lo->ldo_tls_cacertdir != NULL) {
379                 Debug( LDAP_DEBUG_ANY, 
380                        "TLS: warning: cacertdir not implemented for gnutls\n",
381                        NULL, NULL, NULL );
382         }
383
384         if (lo->ldo_tls_cacertfile != NULL) {
385                 rc = gnutls_certificate_set_x509_trust_file( 
386                         ((ldap_pvt_tls_ctx_t*) lo->ldo_tls_ctx)->cred,
387                         lo->ldo_tls_cacertfile,
388                         GNUTLS_X509_FMT_PEM );
389                 if ( rc < 0 ) goto error_exit;
390         }
391
392         if ( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) {
393                 rc = gnutls_certificate_set_x509_key_file( 
394                         ((ldap_pvt_tls_ctx_t*) lo->ldo_tls_ctx)->cred,
395                         lo->ldo_tls_certfile,
396                         lo->ldo_tls_keyfile,
397                         GNUTLS_X509_FMT_PEM );
398                 if ( rc ) goto error_exit;
399         } else if ( lo->ldo_tls_certfile || lo->ldo_tls_keyfile ) {
400                 Debug( LDAP_DEBUG_ANY, 
401                        "TLS: only one of certfile and keyfile specified\n",
402                        NULL, NULL, NULL );
403                 rc = 1;
404                 goto error_exit;
405         }
406
407         if ( lo->ldo_tls_dhfile ) {
408                 Debug( LDAP_DEBUG_ANY, 
409                        "TLS: warning: ignoring dhfile\n", 
410                        NULL, NULL, NULL );
411         }
412
413         if ( lo->ldo_tls_crlfile ) {
414                 rc = gnutls_certificate_set_x509_crl_file( 
415                         ((ldap_pvt_tls_ctx_t*) lo->ldo_tls_ctx)->cred,
416                         lo->ldo_tls_crlfile,
417                         GNUTLS_X509_FMT_PEM );
418                 if ( rc < 0 ) goto error_exit;
419         }
420         if ( is_server ) {
421                 gnutls_dh_params_init (&((ldap_pvt_tls_ctx_t*) 
422                                         lo->ldo_tls_ctx)->dh_params);
423                 gnutls_dh_params_generate2 (((ldap_pvt_tls_ctx_t*) 
424                                                  lo->ldo_tls_ctx)->dh_params, 
425                                                 DH_BITS);
426         }
427
428 error_exit:
429 #ifdef HAVE_EBCDIC
430         LDAP_FREE( ciphersuite );
431         LDAP_FREE( cacertfile );
432         LDAP_FREE( cacertdir );
433         LDAP_FREE( certfile );
434         LDAP_FREE( keyfile );
435         LDAP_FREE( dhfile );
436         LDAP_FREE( crlfile );
437 #endif
438         return rc;
439 }
440
441 /*
442  * initialize the default context
443  */
444 int
445 ldap_pvt_tls_init_def_ctx( int is_server )
446 {
447         return ldap_int_tls_init_ctx( LDAP_INT_GLOBAL_OPT(), is_server );
448 }
449
450 static ldap_pvt_gnutls_session_t *
451 alloc_handle( void *ctx_arg, int is_server )
452 {
453         ldap_pvt_tls_ctx_t *ctx;
454         ldap_pvt_gnutls_session_t *session;
455
456         if ( ctx_arg ) {
457                 ctx = (ldap_pvt_tls_ctx_t *) ctx_arg;
458         } else {
459                 struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
460                 if ( ldap_pvt_tls_init_def_ctx( is_server ) < 0 ) return NULL;
461                 ctx = lo->ldo_tls_ctx;
462         }
463
464         session = ldap_pvt_gnutls_session_new( ctx, is_server );
465         if ( session == NULL ) {
466                 Debug( LDAP_DEBUG_ANY,"TLS: can't create ssl handle.\n",0,0,0);
467                 return NULL;
468         }
469         return session;
470 }
471
472 static int
473 update_flags( Sockbuf *sb, 
474               ldap_pvt_gnutls_session_t * session,
475               int rc )
476 {
477         sb->sb_trans_needs_read  = 0;
478         sb->sb_trans_needs_write = 0;
479
480         if ( rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN )
481                 return 0;
482
483         switch (gnutls_record_get_direction (session->session)) {
484         case 0: 
485                 sb->sb_trans_needs_read = 1;
486                 return 1;
487         case 1:
488                 sb->sb_trans_needs_write = 1;
489                 return 1;
490         }
491         return 0;
492 }
493
494 /*
495  * TLS support for LBER Sockbufs
496  */
497
498 struct tls_data {
499         ldap_pvt_gnutls_session_t       *session;
500         Sockbuf_IO_Desc         *sbiod;
501 };
502
503 static ssize_t
504 sb_gtls_recv( gnutls_transport_ptr_t ptr, void *buf, size_t len )
505 {
506         struct tls_data         *p;
507
508         if ( buf == NULL || len <= 0 ) return 0;
509
510         p = (struct tls_data *)ptr;
511
512         if ( p == NULL || p->sbiod == NULL ) {
513                 return 0;
514         }
515
516         return LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
517 }
518
519 static ssize_t
520 sb_gtls_send( gnutls_transport_ptr_t ptr, const void *buf, size_t len )
521 {
522         struct tls_data         *p;
523         
524         if ( buf == NULL || len <= 0 ) return 0;
525         
526         p = (struct tls_data *)ptr;
527
528         if ( p == NULL || p->sbiod == NULL ) {
529                 return 0;
530         }
531
532         return LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
533 }
534
535 static int
536 sb_tls_setup( Sockbuf_IO_Desc *sbiod, void *arg )
537 {
538         struct tls_data         *p;
539         ldap_pvt_gnutls_session_t       *session = arg;
540
541         assert( sbiod != NULL );
542
543         p = LBER_MALLOC( sizeof( *p ) );
544         if ( p == NULL ) {
545                 return -1;
546         }
547         
548         gnutls_transport_set_ptr( session->session, (gnutls_transport_ptr)p );
549         gnutls_transport_set_pull_function( session->session, sb_gtls_recv );
550         gnutls_transport_set_push_function( session->session, sb_gtls_send );
551         p->session = arg;
552         p->sbiod = sbiod;
553         sbiod->sbiod_pvt = p;
554         return 0;
555 }
556
557 static int
558 sb_tls_remove( Sockbuf_IO_Desc *sbiod )
559 {
560         struct tls_data         *p;
561         
562         assert( sbiod != NULL );
563         assert( sbiod->sbiod_pvt != NULL );
564
565         p = (struct tls_data *)sbiod->sbiod_pvt;
566         gnutls_deinit ( p->session->session );
567         LBER_FREE( p->session );
568         LBER_FREE( sbiod->sbiod_pvt );
569         sbiod->sbiod_pvt = NULL;
570         return 0;
571 }
572
573 static int
574 sb_tls_close( Sockbuf_IO_Desc *sbiod )
575 {
576         struct tls_data         *p;
577         
578         assert( sbiod != NULL );
579         assert( sbiod->sbiod_pvt != NULL );
580
581         p = (struct tls_data *)sbiod->sbiod_pvt;
582         gnutls_bye ( p->session->session, GNUTLS_SHUT_RDWR );
583         return 0;
584 }
585
586 static int
587 sb_tls_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
588 {
589         struct tls_data         *p;
590         
591         assert( sbiod != NULL );
592         assert( sbiod->sbiod_pvt != NULL );
593
594         p = (struct tls_data *)sbiod->sbiod_pvt;
595         
596         if ( opt == LBER_SB_OPT_GET_SSL ) {
597                 *((ldap_pvt_gnutls_session_t **)arg) = p->session;
598                 return 1;
599                 
600         } else if ( opt == LBER_SB_OPT_DATA_READY ) {
601                 if( gnutls_record_check_pending( p->session->session ) > 0 ) {
602                         return 1;
603                 }
604         }
605         
606         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
607 }
608
609 static ber_slen_t
610 sb_tls_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
611 {
612         struct tls_data         *p;
613         ber_slen_t              ret;
614         int                     err;
615
616         assert( sbiod != NULL );
617         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
618
619         p = (struct tls_data *)sbiod->sbiod_pvt;
620
621         ret = gnutls_record_recv ( p->session->session, buf, len );
622         switch (ret) {
623         case GNUTLS_E_INTERRUPTED:
624         case GNUTLS_E_AGAIN:
625                 sbiod->sbiod_sb->sb_trans_needs_read = 1;
626                 sock_errset(EWOULDBLOCK);
627                 ret = 0;
628                 break;
629         case GNUTLS_E_REHANDSHAKE:
630                 for ( ret = gnutls_handshake ( p->session->session );
631                       ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN;
632                       ret = gnutls_handshake ( p->session->session ) );
633                 sbiod->sbiod_sb->sb_trans_needs_read = 1;
634                 ret = 0;
635                 break;
636         default:
637                 sbiod->sbiod_sb->sb_trans_needs_read = 0;
638         }
639         return ret;
640 }
641
642 static ber_slen_t
643 sb_tls_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
644 {
645         struct tls_data         *p;
646         ber_slen_t              ret;
647         int                     err;
648
649         assert( sbiod != NULL );
650         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
651
652         p = (struct tls_data *)sbiod->sbiod_pvt;
653
654         ret = gnutls_record_send ( p->session->session, (char *)buf, len );
655
656         if ( ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ) {
657                 sbiod->sbiod_sb->sb_trans_needs_write = 1;
658                 sock_errset(EWOULDBLOCK);
659                 ret = 0;
660         } else {
661                 sbiod->sbiod_sb->sb_trans_needs_write = 0;
662         }
663         return ret;
664 }
665
666 static Sockbuf_IO sb_tls_sbio =
667 {
668         sb_tls_setup,           /* sbi_setup */
669         sb_tls_remove,          /* sbi_remove */
670         sb_tls_ctrl,            /* sbi_ctrl */
671         sb_tls_read,            /* sbi_read */
672         sb_tls_write,           /* sbi_write */
673         sb_tls_close            /* sbi_close */
674 };
675
676 static int
677 ldap_int_tls_cert_verify( ldap_pvt_gnutls_session_t *ssl )
678 {
679         unsigned int status = 0;
680         int err;
681         time_t now = time(0);
682
683         err = gnutls_certificate_verify_peers2( ssl->session, &status );
684         if ( err < 0 ) {
685                 Debug( LDAP_DEBUG_ANY,"TLS: gnutls_certificate_verify_peers2 failed %d\n",
686                         err,0,0 );
687                 return -1;
688         }
689         if ( status ) {
690                 Debug( LDAP_DEBUG_TRACE,"TLS: peer cert untrusted or revoked (0x%x)\n",
691                         status, 0,0 );
692                 return -1;
693         }
694         if ( gnutls_certificate_expiration_time_peers( ssl->session ) < now ) {
695                 Debug( LDAP_DEBUG_ANY, "TLS: peer certificate is expired\n",
696                         0, 0, 0 );
697                 return -1;
698         }
699         if ( gnutls_certificate_activation_time_peers( ssl->session ) > now ) {
700                 Debug( LDAP_DEBUG_ANY, "TLS: peer certificate not yet active\n",
701                         0, 0, 0 );
702                 return -1;
703         }
704         return 0;
705 }
706
707 /*
708  * Call this to do a TLS connect on a sockbuf. ctx_arg can be
709  * a SSL_CTX * or NULL, in which case the default ctx is used.
710  *
711  * Return value:
712  *
713  *  0 - Success. Connection is ready for communication.
714  * <0 - Error. Can't create a TLS stream.
715  * >0 - Partial success.
716  *        Do a select (using information from lber_pvt_sb_needs_{read,write}
717  *              and call again.
718  */
719
720 static int
721 ldap_int_tls_connect( LDAP *ld, LDAPConn *conn )
722 {
723         Sockbuf *sb = conn->lconn_sb;
724         int     err;
725         ldap_pvt_gnutls_session_t       *ssl;
726
727         if ( HAS_TLS( sb ) ) {
728                 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl );
729
730         } else {
731                 struct ldapoptions *lo;
732                 ldap_pvt_tls_ctx_t *ctx;
733
734                 ctx = ld->ld_options.ldo_tls_ctx;
735
736                 ssl = alloc_handle( ctx, 0 );
737
738                 if ( ssl == NULL ) return -1;
739
740 #ifdef LDAP_DEBUG
741                 ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
742                         LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
743 #endif
744                 ber_sockbuf_add_io( sb, &sb_tls_sbio,
745                         LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );
746
747                 lo = LDAP_INT_GLOBAL_OPT();   
748                 if( ctx == NULL ) {
749                         ctx = lo->ldo_tls_ctx;
750                         ldap_pvt_tls_ctx_ref( ctx );
751                         ld->ld_options.ldo_tls_ctx = ctx;
752                 }
753                 if ( ld->ld_options.ldo_tls_connect_cb )
754                         ld->ld_options.ldo_tls_connect_cb( ld, ssl, ctx,
755                         ld->ld_options.ldo_tls_connect_arg );
756                 if ( lo && lo->ldo_tls_connect_cb && lo->ldo_tls_connect_cb !=
757                         ld->ld_options.ldo_tls_connect_cb )
758                         lo->ldo_tls_connect_cb( ld, ssl, ctx, lo->ldo_tls_connect_arg );
759         }
760
761         err = gnutls_handshake( ssl->session );
762
763 #ifdef HAVE_WINSOCK
764         errno = WSAGetLastError();
765 #endif
766
767         if ( err < 0 ) {
768                 if ( update_flags( sb, ssl, err )) {
769                         return 1;
770                 }
771
772                 if ( ld->ld_error ) {
773                         LDAP_FREE( ld->ld_error );
774                 }
775                 ld->ld_error = LDAP_STRDUP(gnutls_strerror( err ));
776 #ifdef HAVE_EBCDIC
777                 if ( ld->ld_error ) __etoa(ld->ld_error);
778 #endif
779
780                 Debug( LDAP_DEBUG_ANY,"TLS: can't connect: %s\n",
781                         ld->ld_error ? ld->ld_error : "" ,0,0);
782
783                 ber_sockbuf_remove_io( sb, &sb_tls_sbio,
784                         LBER_SBIOD_LEVEL_TRANSPORT );
785 #ifdef LDAP_DEBUG
786                 ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
787                         LBER_SBIOD_LEVEL_TRANSPORT );
788 #endif
789                 return -1;
790         }
791
792         if ( ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER ) {
793                 err = ldap_int_tls_cert_verify( ssl );
794                 if ( err && ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW )
795                         return err;
796         }
797         return 0;
798 }
799
800 /*
801  * Call this to do a TLS accept on a sockbuf.
802  * Everything else is the same as with tls_connect.
803  */
804 int
805 ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg )
806 {
807         int     err;
808         ldap_pvt_gnutls_session_t       *ssl;
809
810         if ( HAS_TLS( sb ) ) {
811                 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl );
812
813         } else {
814                 ssl = alloc_handle( ctx_arg, 1 );
815                 if ( ssl == NULL ) return -1;
816
817 #ifdef LDAP_DEBUG
818                 ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
819                         LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
820 #endif
821                 ber_sockbuf_add_io( sb, &sb_tls_sbio,
822                         LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );
823         }
824
825         err = gnutls_handshake( ssl->session );
826
827 #ifdef HAVE_WINSOCK
828         errno = WSAGetLastError();
829 #endif
830         if ( err < 0 ) {
831                 if ( update_flags( sb, ssl, err )) return 1;
832
833                 Debug( LDAP_DEBUG_ANY,"TLS: can't accept: %s.\n",
834                         gnutls_strerror( err ),0,0 );
835
836                 ber_sockbuf_remove_io( sb, &sb_tls_sbio,
837                         LBER_SBIOD_LEVEL_TRANSPORT );
838 #ifdef LDAP_DEBUG
839                 ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
840                         LBER_SBIOD_LEVEL_TRANSPORT );
841 #endif
842                 return -1;
843         }
844         if ( ssl->ctx->lo->ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER ) {
845                 err = ldap_int_tls_cert_verify( ssl );
846                 if ( err && ssl->ctx->lo->ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW )
847                         return err;
848         }
849
850         return 0;
851 }
852
853 int
854 ldap_pvt_tls_inplace ( Sockbuf *sb )
855 {
856         return HAS_TLS( sb ) ? 1 : 0;
857 }
858
859 int
860 ldap_tls_inplace( LDAP *ld )
861 {
862         Sockbuf         *sb = NULL;
863
864         if ( ld->ld_defconn && ld->ld_defconn->lconn_sb ) {
865                 sb = ld->ld_defconn->lconn_sb;
866
867         } else if ( ld->ld_sb ) {
868                 sb = ld->ld_sb;
869
870         } else {
871                 return 0;
872         }
873
874         return ldap_pvt_tls_inplace( sb );
875 }
876
877 static void
878 x509_cert_get_dn( struct berval *cert, struct berval *dn, int get_subject )
879 {
880         BerElementBuffer berbuf;
881         BerElement *ber = (BerElement *)&berbuf;
882         ber_tag_t tag;
883         ber_len_t len;
884         ber_int_t i;
885
886         ber_init2( ber, cert, LBER_USE_DER );
887         tag = ber_skip_tag( ber, &len );        /* Sequence */
888         tag = ber_skip_tag( ber, &len );        /* Sequence */
889         tag = ber_skip_tag( ber, &len );        /* Context + Constructed (version) */
890         if ( tag == 0xa0 )      /* Version is optional */
891                 tag = ber_get_int( ber, &i );   /* Int: Version */
892         tag = ber_get_int( ber, &i );   /* Int: Serial */
893         tag = ber_skip_tag( ber, &len );        /* Sequence: Signature */
894         ber_skip_data( ber, len );
895         if ( !get_subject ) {
896                 tag = ber_peek_tag( ber, &len );        /* Sequence: Issuer DN */
897         } else {
898                 tag = ber_skip_tag( ber, &len );
899                 ber_skip_data( ber, len );
900                 tag = ber_skip_tag( ber, &len );        /* Sequence: Validity */
901                 ber_skip_data( ber, len );
902                 tag = ber_peek_tag( ber, &len );        /* Sequence: Subject DN */
903         }
904         len = ber_ptrlen( ber );
905         dn->bv_val = cert->bv_val + len;
906         dn->bv_len = cert->bv_len - len;
907 }
908
909 static int
910 tls_get_cert_dn( ldap_pvt_gnutls_session_t *session )
911 {
912         if ( !session->peer_der_dn.bv_val ) {
913                 const gnutls_datum_t *peer_cert_list;
914                 int list_size;
915                 struct berval bv;
916
917                 peer_cert_list = gnutls_certificate_get_peers( session->session, 
918                                                         &list_size );
919                 if ( !peer_cert_list ) return LDAP_INVALID_CREDENTIALS;
920
921                 bv.bv_len = peer_cert_list->size;
922                 bv.bv_val = peer_cert_list->data;
923
924                 x509_cert_get_dn( &bv, &session->peer_der_dn, 1 );
925         }
926         return 0;
927 }
928
929 int
930 ldap_pvt_tls_get_peer_dn( void *s, struct berval *dn,
931         LDAPDN_rewrite_dummy *func, unsigned flags )
932 {
933         ldap_pvt_gnutls_session_t *session = s;
934         int rc;
935
936         rc = tls_get_cert_dn( session );
937         if ( rc ) return rc;
938
939         rc = ldap_X509dn2bv( &session->peer_der_dn, dn, 
940                             (LDAPDN_rewrite_func *)func, flags);
941         return rc;
942 }
943
944 /* what kind of hostname were we given? */
945 #define IS_DNS  0
946 #define IS_IP4  1
947 #define IS_IP6  2
948
949 int
950 ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in )
951 {
952         ldap_pvt_gnutls_session_t *session = s;
953         int i, ret;
954         const gnutls_datum_t *peer_cert_list;
955         int list_size;
956         struct berval bv;
957         char altname[NI_MAXHOST];
958         size_t altnamesize;
959
960         gnutls_x509_crt_t cert;
961         gnutls_datum_t *x;
962         const char *name;
963         char *ptr;
964         char *domain = NULL;
965 #ifdef LDAP_PF_INET6
966         struct in6_addr addr;
967 #else
968         struct in_addr addr;
969 #endif
970         int n, len1 = 0, len2 = 0;
971         int ntype = IS_DNS;
972         time_t now = time(0);
973
974         if( ldap_int_hostname &&
975                 ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
976         {
977                 name = ldap_int_hostname;
978         } else {
979                 name = name_in;
980         }
981
982         peer_cert_list = gnutls_certificate_get_peers( session->session, 
983                                                 &list_size );
984         if ( !peer_cert_list ) {
985                 Debug( LDAP_DEBUG_ANY,
986                         "TLS: unable to get peer certificate.\n",
987                         0, 0, 0 );
988                 /* If this was a fatal condition, things would have
989                  * aborted long before now.
990                  */
991                 return LDAP_SUCCESS;
992         }
993         ret = gnutls_x509_crt_init( &cert );
994         if ( ret < 0 )
995                 return LDAP_LOCAL_ERROR;
996         ret = gnutls_x509_crt_import( cert, peer_cert_list, GNUTLS_X509_FMT_DER );
997         if ( ret ) {
998                 gnutls_x509_crt_deinit( cert );
999                 return LDAP_LOCAL_ERROR;
1000         }
1001
1002 #ifdef LDAP_PF_INET6
1003         if (name[0] == '[' && strchr(name, ']')) {
1004                 char *n2 = ldap_strdup(name+1);
1005                 *strchr(n2, ']') = 2;
1006                 if (inet_pton(AF_INET6, n2, &addr))
1007                         ntype = IS_IP6;
1008                 LDAP_FREE(n2);
1009         } else 
1010 #endif
1011         if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
1012                 if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
1013         }
1014         
1015         if (ntype == IS_DNS) {
1016                 len1 = strlen(name);
1017                 domain = strchr(name, '.');
1018                 if (domain) {
1019                         len2 = len1 - (domain-name);
1020                 }
1021         }
1022
1023         for ( i=0, ret=0; ret >= 0; i++ ) {
1024                 altnamesize = sizeof(altname);
1025                 ret = gnutls_x509_crt_get_subject_alt_name( cert, i, 
1026                         altname, &altnamesize, NULL );
1027                 if ( ret < 0 ) break;
1028
1029                 /* ignore empty */
1030                 if ( altnamesize == 0 ) continue;
1031
1032                 if ( ret == GNUTLS_SAN_DNSNAME ) {
1033                         if (ntype != IS_DNS) continue;
1034         
1035                         /* Is this an exact match? */
1036                         if ((len1 == altnamesize) && !strncasecmp(name, altname, len1)) {
1037                                 break;
1038                         }
1039
1040                         /* Is this a wildcard match? */
1041                         if (domain && (altname[0] == '*') && (altname[1] == '.') &&
1042                                 (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2))
1043                         {
1044                                 break;
1045                         }
1046                 } else if ( ret == GNUTLS_SAN_IPADDRESS ) {
1047                         if (ntype == IS_DNS) continue;
1048
1049 #ifdef LDAP_PF_INET6
1050                         if (ntype == IS_IP6 && altnamesize != sizeof(struct in6_addr)) {
1051                                 continue;
1052                         } else
1053 #endif
1054                         if (ntype == IS_IP4 && altnamesize != sizeof(struct in_addr)) {
1055                                 continue;
1056                         }
1057                         if (!memcmp(altname, &addr, altnamesize)) {
1058                                 break;
1059                         }
1060                 }
1061         }
1062         if ( ret >= 0 ) {
1063                 ret = LDAP_SUCCESS;
1064         } else {
1065                 altnamesize = sizeof(altname);
1066                 ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
1067                         0, 0, altname, &altnamesize );
1068                 if ( ret < 0 ) {
1069                         Debug( LDAP_DEBUG_ANY,
1070                                 "TLS: unable to get common name from peer certificate.\n",
1071                                 0, 0, 0 );
1072                         ret = LDAP_CONNECT_ERROR;
1073                         if ( ld->ld_error ) {
1074                                 LDAP_FREE( ld->ld_error );
1075                         }
1076                         ld->ld_error = LDAP_STRDUP(
1077                                 _("TLS: unable to get CN from peer certificate"));
1078
1079                 } else {
1080                         ret = LDAP_LOCAL_ERROR;
1081                         if ( len1 == altnamesize && strncasecmp(name, altname, altnamesize) == 0 ) {
1082                                 ret = LDAP_SUCCESS;
1083
1084                         } else if (( altname[0] == '*' ) && ( altname[1] == '.' )) {
1085                                         /* Is this a wildcard match? */
1086                                 if( domain &&
1087                                         (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) {
1088                                         ret = LDAP_SUCCESS;
1089                                 }
1090                         }
1091                 }
1092
1093                 if( ret == LDAP_LOCAL_ERROR ) {
1094                         altname[altnamesize] = '\0';
1095                         Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
1096                                 "common name in certificate (%s).\n", 
1097                                 name, altname, 0 );
1098                         ret = LDAP_CONNECT_ERROR;
1099                         if ( ld->ld_error ) {
1100                                 LDAP_FREE( ld->ld_error );
1101                         }
1102                         ld->ld_error = LDAP_STRDUP(
1103                                 _("TLS: hostname does not match CN in peer certificate"));
1104                 }
1105         }
1106         gnutls_x509_crt_deinit( cert );
1107         return ret;
1108 }
1109
1110 const char *
1111 ldap_pvt_tls_get_peer_issuer( void *s )
1112 {
1113 #if 0   /* currently unused; see ldap_pvt_tls_get_peer_dn() if needed */
1114         gnutls_datum_t *x;
1115         gnutls_x509_dn *xn;
1116         char buf[2048], *p;
1117
1118         x = SSL_get_peer_certificate((ldap_pvt_gnutls_session_t *)s);
1119
1120         if (!x) return NULL;
1121         
1122         xn = X509_get_issuer_name(x);
1123         p = LDAP_STRDUP(X509_NAME_oneline(xn, buf, sizeof(buf)));
1124         X509_free(x);
1125         return p;
1126 #else
1127         return NULL;
1128 #endif
1129 }
1130
1131 int
1132 ldap_int_tls_config( LDAP *ld, int option, const char *arg )
1133 {
1134         int i;
1135
1136         switch( option ) {
1137         case LDAP_OPT_X_TLS_CACERTFILE:
1138         case LDAP_OPT_X_TLS_CACERTDIR:
1139         case LDAP_OPT_X_TLS_CERTFILE:
1140         case LDAP_OPT_X_TLS_KEYFILE:
1141         case LDAP_OPT_X_TLS_RANDOM_FILE:
1142         case LDAP_OPT_X_TLS_CIPHER_SUITE:
1143         case LDAP_OPT_X_TLS_DHFILE:
1144         case LDAP_OPT_X_TLS_CRLFILE:
1145                 return ldap_pvt_tls_set_option( ld, option, (void *) arg );
1146
1147         case LDAP_OPT_X_TLS_REQUIRE_CERT:
1148         case LDAP_OPT_X_TLS:
1149                 i = -1;
1150                 if ( strcasecmp( arg, "never" ) == 0 ) {
1151                         i = LDAP_OPT_X_TLS_NEVER ;
1152
1153                 } else if ( strcasecmp( arg, "demand" ) == 0 ) {
1154                         i = LDAP_OPT_X_TLS_DEMAND ;
1155
1156                 } else if ( strcasecmp( arg, "allow" ) == 0 ) {
1157                         i = LDAP_OPT_X_TLS_ALLOW ;
1158
1159                 } else if ( strcasecmp( arg, "try" ) == 0 ) {
1160                         i = LDAP_OPT_X_TLS_TRY ;
1161
1162                 } else if ( ( strcasecmp( arg, "hard" ) == 0 ) ||
1163                         ( strcasecmp( arg, "on" ) == 0 ) ||
1164                         ( strcasecmp( arg, "yes" ) == 0) ||
1165                         ( strcasecmp( arg, "true" ) == 0 ) )
1166                 {
1167                         i = LDAP_OPT_X_TLS_HARD ;
1168                 }
1169
1170                 if (i >= 0) {
1171                         return ldap_pvt_tls_set_option( ld, option, &i );
1172                 }
1173                 return -1;
1174         }
1175         return -1;
1176 }
1177
1178 int
1179 ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg )
1180 {
1181         struct ldapoptions *lo;
1182
1183         if( ld != NULL ) {
1184                 assert( LDAP_VALID( ld ) );
1185
1186                 if( !LDAP_VALID( ld ) ) {
1187                         return LDAP_OPT_ERROR;
1188                 }
1189
1190                 lo = &ld->ld_options;
1191
1192         } else {
1193                 /* Get pointer to global option structure */
1194                 lo = LDAP_INT_GLOBAL_OPT();   
1195                 if ( lo == NULL ) {
1196                         return LDAP_NO_MEMORY;
1197                 }
1198         }
1199
1200         switch( option ) {
1201         case LDAP_OPT_X_TLS:
1202                 *(int *)arg = lo->ldo_tls_mode;
1203                 break;
1204         case LDAP_OPT_X_TLS_CTX:
1205                 *(void **)arg = lo->ldo_tls_ctx;
1206                 if ( lo->ldo_tls_ctx ) {
1207                         ldap_pvt_tls_ctx_ref( lo->ldo_tls_ctx );
1208                 }
1209                 break;
1210         case LDAP_OPT_X_TLS_CACERTFILE:
1211                 *(char **)arg = lo->ldo_tls_cacertfile ?
1212                         LDAP_STRDUP( lo->ldo_tls_cacertfile ) : NULL;
1213                 break;
1214         case LDAP_OPT_X_TLS_CACERTDIR:
1215                 *(char **)arg = lo->ldo_tls_cacertdir ?
1216                         LDAP_STRDUP( lo->ldo_tls_cacertdir ) : NULL;
1217                 break;
1218         case LDAP_OPT_X_TLS_CERTFILE:
1219                 *(char **)arg = lo->ldo_tls_certfile ?
1220                         LDAP_STRDUP( lo->ldo_tls_certfile ) : NULL;
1221                 break;
1222         case LDAP_OPT_X_TLS_KEYFILE:
1223                 *(char **)arg = lo->ldo_tls_keyfile ?
1224                         LDAP_STRDUP( lo->ldo_tls_keyfile ) : NULL;
1225                 break;
1226         case LDAP_OPT_X_TLS_DHFILE:
1227                 *(char **)arg = lo->ldo_tls_dhfile ?
1228                         LDAP_STRDUP( lo->ldo_tls_dhfile ) : NULL;
1229                 break;
1230         case LDAP_OPT_X_TLS_CRLFILE:
1231                 *(char **)arg = lo->ldo_tls_crlfile ?
1232                         LDAP_STRDUP( lo->ldo_tls_crlfile ) : NULL;
1233                 break;
1234         case LDAP_OPT_X_TLS_REQUIRE_CERT:
1235                 *(int *)arg = lo->ldo_tls_require_cert;
1236                 break;
1237 #ifdef HAVE_OPENSSL_CRL
1238         case LDAP_OPT_X_TLS_CRLCHECK:
1239                 *(int *)arg = lo->ldo_tls_crlcheck;
1240                 break;
1241 #endif
1242         case LDAP_OPT_X_TLS_CIPHER_SUITE:
1243                 *(char **)arg = lo->ldo_tls_ciphersuite ?
1244                         LDAP_STRDUP( lo->ldo_tls_ciphersuite ) : NULL;
1245                 break;
1246         case LDAP_OPT_X_TLS_RANDOM_FILE:
1247                 *(char **)arg = NULL;
1248                 break;
1249         case LDAP_OPT_X_TLS_SSL_CTX: {
1250                 void *retval = 0;
1251                 if ( ld != NULL ) {
1252                         LDAPConn *conn = ld->ld_defconn;
1253                         if ( conn != NULL ) {
1254                                 Sockbuf *sb = conn->lconn_sb;
1255                                 retval = ldap_pvt_tls_sb_ctx( sb );
1256                         }
1257                 }
1258                 *(void **)arg = retval;
1259                 break;
1260         }
1261         case LDAP_OPT_X_TLS_CONNECT_CB:
1262                 *(LDAP_TLS_CONNECT_CB **)arg = lo->ldo_tls_connect_cb;
1263                 break;
1264         case LDAP_OPT_X_TLS_CONNECT_ARG:
1265                 *(void **)arg = lo->ldo_tls_connect_arg;
1266                 break;
1267         default:
1268                 return -1;
1269         }
1270         return 0;
1271 }
1272
1273 int
1274 ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
1275 {
1276         struct ldapoptions *lo;
1277
1278         if( ld != NULL ) {
1279                 assert( LDAP_VALID( ld ) );
1280
1281                 if( !LDAP_VALID( ld ) ) {
1282                         return LDAP_OPT_ERROR;
1283                 }
1284
1285                 lo = &ld->ld_options;
1286
1287         } else {
1288                 /* Get pointer to global option structure */
1289                 lo = LDAP_INT_GLOBAL_OPT();   
1290                 if ( lo == NULL ) {
1291                         return LDAP_NO_MEMORY;
1292                 }
1293         }
1294
1295         switch( option ) {
1296         case LDAP_OPT_X_TLS:
1297                 if ( !arg ) return -1;
1298
1299                 switch( *(int *) arg ) {
1300                 case LDAP_OPT_X_TLS_NEVER:
1301                 case LDAP_OPT_X_TLS_DEMAND:
1302                 case LDAP_OPT_X_TLS_ALLOW:
1303                 case LDAP_OPT_X_TLS_TRY:
1304                 case LDAP_OPT_X_TLS_HARD:
1305                         if (lo != NULL) {
1306                                 lo->ldo_tls_mode = *(int *)arg;
1307                         }
1308
1309                         return 0;
1310                 }
1311                 return -1;
1312
1313         case LDAP_OPT_X_TLS_CTX:
1314                 if ( lo->ldo_tls_ctx )
1315                         ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
1316                 lo->ldo_tls_ctx = arg;
1317                 ldap_pvt_tls_ctx_ref( lo->ldo_tls_ctx );
1318                 return 0;
1319         case LDAP_OPT_X_TLS_CONNECT_CB:
1320                 lo->ldo_tls_connect_cb = (LDAP_TLS_CONNECT_CB *)arg;
1321                 return 0;
1322         case LDAP_OPT_X_TLS_CONNECT_ARG:
1323                 lo->ldo_tls_connect_arg = arg;
1324                 return 0;
1325         case LDAP_OPT_X_TLS_CACERTFILE:
1326                 if ( lo->ldo_tls_cacertfile ) LDAP_FREE( lo->ldo_tls_cacertfile );
1327                 lo->ldo_tls_cacertfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
1328                 return 0;
1329         case LDAP_OPT_X_TLS_CACERTDIR:
1330                 if ( lo->ldo_tls_cacertdir ) LDAP_FREE( lo->ldo_tls_cacertdir );
1331                 lo->ldo_tls_cacertdir = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
1332                 return 0;
1333         case LDAP_OPT_X_TLS_CERTFILE:
1334                 if ( lo->ldo_tls_certfile ) LDAP_FREE( lo->ldo_tls_certfile );
1335                 lo->ldo_tls_certfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
1336                 return 0;
1337         case LDAP_OPT_X_TLS_KEYFILE:
1338                 if ( lo->ldo_tls_keyfile ) LDAP_FREE( lo->ldo_tls_keyfile );
1339                 lo->ldo_tls_keyfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
1340                 return 0;
1341         case LDAP_OPT_X_TLS_DHFILE:
1342                 if ( lo->ldo_tls_dhfile ) LDAP_FREE( lo->ldo_tls_dhfile );
1343                 lo->ldo_tls_dhfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
1344                 return 0;
1345         case LDAP_OPT_X_TLS_CRLFILE:
1346                 if ( lo->ldo_tls_crlfile ) LDAP_FREE( lo->ldo_tls_crlfile );
1347                 lo->ldo_tls_crlfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
1348                 return 0;
1349         case LDAP_OPT_X_TLS_REQUIRE_CERT:
1350                 if ( !arg ) return -1;
1351                 switch( *(int *) arg ) {
1352                 case LDAP_OPT_X_TLS_NEVER:
1353                 case LDAP_OPT_X_TLS_DEMAND:
1354                 case LDAP_OPT_X_TLS_ALLOW:
1355                 case LDAP_OPT_X_TLS_TRY:
1356                 case LDAP_OPT_X_TLS_HARD:
1357                         lo->ldo_tls_require_cert = * (int *) arg;
1358                         return 0;
1359                 }
1360                 return -1;
1361 #ifdef HAVE_OPENSSL_CRL
1362         case LDAP_OPT_X_TLS_CRLCHECK:
1363                 if ( !arg ) return -1;
1364                 switch( *(int *) arg ) {
1365                 case LDAP_OPT_X_TLS_CRL_NONE:
1366                 case LDAP_OPT_X_TLS_CRL_PEER:
1367                 case LDAP_OPT_X_TLS_CRL_ALL:
1368                         lo->ldo_tls_crlcheck = * (int *) arg;
1369                         return 0;
1370                 }
1371                 return -1;
1372 #endif
1373         case LDAP_OPT_X_TLS_CIPHER_SUITE:
1374                 if ( lo->ldo_tls_ciphersuite ) LDAP_FREE( lo->ldo_tls_ciphersuite );
1375                 lo->ldo_tls_ciphersuite = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
1376                 return 0;
1377
1378         case LDAP_OPT_X_TLS_RANDOM_FILE:
1379                 return 0;
1380                 break;
1381
1382         case LDAP_OPT_X_TLS_NEWCTX:
1383                 if ( !arg ) return -1;
1384                 if ( lo->ldo_tls_ctx )
1385                         ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
1386                 lo->ldo_tls_ctx = NULL;
1387                 return ldap_int_tls_init_ctx( lo, *(int *)arg );
1388         default:
1389                 return -1;
1390         }
1391         return 0;
1392 }
1393
1394 int
1395 ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
1396 {
1397         Sockbuf *sb = conn->lconn_sb;
1398         char *host;
1399         void *ssl;
1400
1401         if( srv ) {
1402                 host = srv->lud_host;
1403         } else {
1404                 host = conn->lconn_server->lud_host;
1405         }
1406
1407         /* avoid NULL host */
1408         if( host == NULL ) {
1409                 host = "localhost";
1410         }
1411
1412         (void) ldap_pvt_tls_init();
1413
1414         /*
1415          * Fortunately, the lib uses blocking io...
1416          */
1417         if ( ldap_int_tls_connect( ld, conn ) < 0 ) {
1418                 ld->ld_errno = LDAP_CONNECT_ERROR;
1419                 return (ld->ld_errno);
1420         }
1421
1422         ssl = ldap_pvt_tls_sb_ctx( sb );
1423         assert( ssl != NULL );
1424
1425         /* 
1426          * compare host with name(s) in certificate
1427          */
1428         if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER) {
1429                 ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host );
1430                 if (ld->ld_errno != LDAP_SUCCESS) {
1431                         return ld->ld_errno;
1432                 }
1433         }
1434
1435         return LDAP_SUCCESS;
1436 }
1437
1438 void *
1439 ldap_pvt_tls_sb_ctx( Sockbuf *sb )
1440 {
1441         void                    *p;
1442         
1443         if (HAS_TLS( sb )) {
1444                 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p );
1445                 return p;
1446         }
1447         return NULL;
1448 }
1449
1450 int
1451 ldap_pvt_tls_get_strength( void *s )
1452 {
1453         ldap_pvt_gnutls_session_t *session = s;
1454         gnutls_cipher_algorithm_t c;
1455
1456         c = gnutls_cipher_get( session->session );
1457         return gnutls_cipher_get_key_size( c );
1458 }
1459
1460 int
1461 ldap_pvt_tls_get_my_dn( void *s, struct berval *dn, LDAPDN_rewrite_dummy *func, unsigned flags )
1462 {
1463         ldap_pvt_gnutls_session_t *session = s;
1464         const gnutls_datum_t *x;
1465         struct berval bv, der_dn;
1466         int rc;
1467
1468         x = gnutls_certificate_get_ours( session->session );
1469
1470         if (!x) return LDAP_INVALID_CREDENTIALS;
1471         
1472         bv.bv_val = x->data;
1473         bv.bv_len = x->size;
1474
1475         x509_cert_get_dn( &bv, &der_dn, 1 );
1476         rc = ldap_X509dn2bv(&der_dn, dn, (LDAPDN_rewrite_func *)func, flags );
1477         return rc;
1478 }
1479
1480 int
1481 ldap_start_tls( LDAP *ld,
1482         LDAPControl **serverctrls,
1483         LDAPControl **clientctrls,
1484         int *msgidp )
1485 {
1486         return ldap_extended_operation( ld, LDAP_EXOP_START_TLS,
1487                 NULL, serverctrls, clientctrls, msgidp );
1488 }
1489
1490 int
1491 ldap_install_tls( LDAP *ld )
1492 {
1493 #ifndef HAVE_TLS
1494         return LDAP_NOT_SUPPORTED;
1495 #else
1496         if ( ldap_tls_inplace( ld ) ) {
1497                 return LDAP_LOCAL_ERROR;
1498         }
1499
1500         return ldap_int_tls_start( ld, ld->ld_defconn, NULL );
1501 #endif
1502 }
1503
1504 int
1505 ldap_start_tls_s ( LDAP *ld,
1506         LDAPControl **serverctrls,
1507         LDAPControl **clientctrls )
1508 {
1509 #ifndef HAVE_TLS
1510         return LDAP_NOT_SUPPORTED;
1511 #else
1512         int rc;
1513         char *rspoid = NULL;
1514         struct berval *rspdata = NULL;
1515
1516         /* XXYYZ: this initiates operation only on default connection! */
1517
1518         if ( ldap_tls_inplace( ld ) ) {
1519                 return LDAP_LOCAL_ERROR;
1520         }
1521
1522         rc = ldap_extended_operation_s( ld, LDAP_EXOP_START_TLS,
1523                 NULL, serverctrls, clientctrls, &rspoid, &rspdata );
1524
1525         if ( rspoid != NULL ) {
1526                 LDAP_FREE(rspoid);
1527         }
1528
1529         if ( rspdata != NULL ) {
1530                 ber_bvfree( rspdata );
1531         }
1532
1533         if ( rc == LDAP_SUCCESS ) {
1534                 rc = ldap_int_tls_start( ld, ld->ld_defconn, NULL );
1535         }
1536
1537         return rc;
1538 #endif
1539 }
1540
1541 /* These tags probably all belong in lber.h, but they're
1542  * not normally encountered when processing LDAP, so maybe
1543  * they belong somewhere else instead.
1544  */
1545
1546 #define LBER_TAG_OID            ((ber_tag_t) 0x06UL)
1547
1548 /* Tags for string types used in a DirectoryString.
1549  *
1550  * Note that IA5string is not one of the defined choices for
1551  * DirectoryString in X.520, but it gets used for email AVAs.
1552  */
1553 #define LBER_TAG_UTF8           ((ber_tag_t) 0x0cUL)
1554 #define LBER_TAG_PRINTABLE      ((ber_tag_t) 0x13UL)
1555 #define LBER_TAG_TELETEX        ((ber_tag_t) 0x14UL)
1556 #define LBER_TAG_IA5            ((ber_tag_t) 0x16UL)
1557 #define LBER_TAG_UNIVERSAL      ((ber_tag_t) 0x1cUL)
1558 #define LBER_TAG_BMP            ((ber_tag_t) 0x1eUL)
1559
1560 static oid_name *
1561 find_oid( struct berval *oid )
1562 {
1563         int i;
1564
1565         for ( i=0; !BER_BVISNULL( &oids[i].oid ); i++ ) {
1566                 if ( oids[i].oid.bv_len != oid->bv_len ) continue;
1567                 if ( !strcmp( oids[i].oid.bv_val, oid->bv_val ))
1568                         return &oids[i];
1569         }
1570         return NULL;
1571 }
1572
1573 /* Convert a structured DN from an X.509 certificate into an LDAPV3 DN.
1574  * x509_name must be raw DER. If func is non-NULL, the
1575  * constructed DN will use numeric OIDs to identify attributeTypes,
1576  * and the func() will be invoked to rewrite the DN with the given
1577  * flags.
1578  *
1579  * Otherwise the DN will use shortNames from a hardcoded table.
1580  */
1581
1582 int
1583 ldap_X509dn2bv( void *x509_name, struct berval *bv, LDAPDN_rewrite_func *func,
1584         unsigned flags )
1585 {
1586         LDAPDN  newDN;
1587         LDAPRDN newRDN;
1588         LDAPAVA *newAVA, *baseAVA;
1589         BerElementBuffer berbuf;
1590         BerElement *ber = (BerElement *)&berbuf;
1591         char oids[8192], *oidptr = oids, *oidbuf = NULL;
1592         void *ptrs[2048];
1593         char *dn_end, *rdn_end;
1594         int i, navas, nrdns, rc = LDAP_SUCCESS;
1595         size_t dnsize, oidrem = sizeof(oids), oidsize = 0;
1596         int csize;
1597         ber_tag_t tag;
1598         ber_len_t len;
1599         oid_name *oidname;
1600
1601         struct berval   Oid, Val, oid2, *in = x509_name;
1602
1603         assert( bv != NULL );
1604
1605         bv->bv_len = 0;
1606         bv->bv_val = NULL;
1607
1608         navas = 0;
1609         nrdns = 0;
1610
1611         /* A DN is a SEQUENCE of RDNs. An RDN is a SET of AVAs.
1612          * An AVA is a SEQUENCE of attr and value.
1613          * Count the number of AVAs and RDNs
1614          */
1615         ber_init2( ber, in, LBER_USE_DER );
1616         tag = ber_peek_tag( ber, &len );
1617         if ( tag != LBER_SEQUENCE )
1618                 return LDAP_DECODING_ERROR;
1619
1620         for ( tag = ber_first_element( ber, &len, &dn_end );
1621                 tag == LBER_SET;
1622                 tag = ber_next_element( ber, &len, dn_end )) {
1623                 nrdns++;
1624                 for ( tag = ber_first_element( ber, &len, &rdn_end );
1625                         tag == LBER_SEQUENCE;
1626                         tag = ber_next_element( ber, &len, rdn_end )) {
1627                         tag = ber_skip_tag( ber, &len );
1628                         ber_skip_data( ber, len );
1629                         navas++;
1630                 }
1631         }
1632
1633         /* Allocate the DN/RDN/AVA stuff as a single block */    
1634         dnsize = sizeof(LDAPRDN) * (nrdns+1);
1635         dnsize += sizeof(LDAPAVA *) * (navas+nrdns);
1636         dnsize += sizeof(LDAPAVA) * navas;
1637         if (dnsize > sizeof(ptrs)) {
1638                 newDN = (LDAPDN)LDAP_MALLOC( dnsize );
1639                 if ( newDN == NULL )
1640                         return LDAP_NO_MEMORY;
1641         } else {
1642                 newDN = (LDAPDN)(char *)ptrs;
1643         }
1644         
1645         newDN[nrdns] = NULL;
1646         newRDN = (LDAPRDN)(newDN + nrdns+1);
1647         newAVA = (LDAPAVA *)(newRDN + navas + nrdns);
1648         baseAVA = newAVA;
1649
1650         /* Rewind and start extracting */
1651         ber_rewind( ber );
1652
1653         tag = ber_first_element( ber, &len, &dn_end );
1654         for ( i = nrdns - 1; i >= 0; i-- ) {
1655                 newDN[i] = newRDN;
1656
1657                 for ( tag = ber_first_element( ber, &len, &rdn_end );
1658                         tag == LBER_SEQUENCE;
1659                         tag = ber_next_element( ber, &len, rdn_end )) {
1660
1661                         *newRDN++ = newAVA;
1662                         tag = ber_skip_tag( ber, &len );
1663                         tag = ber_get_stringbv( ber, &Oid, 0 );
1664                         if ( tag != LBER_TAG_OID ) {
1665                                 rc = LDAP_DECODING_ERROR;
1666                                 goto nomem;
1667                         }
1668
1669                         oid2.bv_val = oidptr;
1670                         oid2.bv_len = oidrem;
1671                         ber_decode_oid( &Oid, &oid2 );
1672                         oidname = find_oid( &oid2 );
1673                         if ( !oidname ) {
1674                                 newAVA->la_attr = oid2;
1675                                 oidptr += oid2.bv_len + 1;
1676                                 oidrem -= oid2.bv_len + 1;
1677
1678                                 /* Running out of OID buffer space? */
1679                                 if (oidrem < 128) {
1680                                         if ( oidsize == 0 ) {
1681                                                 oidsize = sizeof(oids) * 2;
1682                                                 oidrem = oidsize;
1683                                                 oidbuf = LDAP_MALLOC( oidsize );
1684                                                 if ( oidbuf == NULL ) goto nomem;
1685                                                 oidptr = oidbuf;
1686                                         } else {
1687                                                 char *old = oidbuf;
1688                                                 oidbuf = LDAP_REALLOC( oidbuf, oidsize*2 );
1689                                                 if ( oidbuf == NULL ) goto nomem;
1690                                                 /* Buffer moved! Fix AVA pointers */
1691                                                 if ( old != oidbuf ) {
1692                                                         LDAPAVA *a;
1693                                                         long dif = oidbuf - old;
1694
1695                                                         for (a=baseAVA; a<=newAVA; a++){
1696                                                                 if (a->la_attr.bv_val >= old &&
1697                                                                         a->la_attr.bv_val <= (old + oidsize))
1698                                                                         a->la_attr.bv_val += dif;
1699                                                         }
1700                                                 }
1701                                                 oidptr = oidbuf + oidsize - oidrem;
1702                                                 oidrem += oidsize;
1703                                                 oidsize *= 2;
1704                                         }
1705                                 }
1706                         } else {
1707                                 if ( func ) {
1708                                         newAVA->la_attr = oidname->oid;
1709                                 } else {
1710                                         newAVA->la_attr = oidname->name;
1711                                 }
1712                         }
1713                         tag = ber_get_stringbv( ber, &Val, 0 );
1714                         switch(tag) {
1715                         case LBER_TAG_UNIVERSAL:
1716                                 /* This uses 32-bit ISO 10646-1 */
1717                                 csize = 4; goto to_utf8;
1718                         case LBER_TAG_BMP:
1719                                 /* This uses 16-bit ISO 10646-1 */
1720                                 csize = 2; goto to_utf8;
1721                         case LBER_TAG_TELETEX:
1722                                 /* This uses 8-bit, assume ISO 8859-1 */
1723                                 csize = 1;
1724 to_utf8:                rc = ldap_ucs_to_utf8s( &Val, csize, &newAVA->la_value );
1725                                 newAVA->la_flags |= LDAP_AVA_FREE_VALUE;
1726                                 if (rc != LDAP_SUCCESS) goto nomem;
1727                                 newAVA->la_flags = LDAP_AVA_NONPRINTABLE;
1728                                 break;
1729                         case LBER_TAG_UTF8:
1730                                 newAVA->la_flags = LDAP_AVA_NONPRINTABLE;
1731                                 /* This is already in UTF-8 encoding */
1732                         case LBER_TAG_IA5:
1733                         case LBER_TAG_PRINTABLE:
1734                                 /* These are always 7-bit strings */
1735                                 newAVA->la_value = Val;
1736                         default:
1737                                 ;
1738                         }
1739                         newAVA->la_private = NULL;
1740                         newAVA->la_flags = LDAP_AVA_STRING;
1741                         newAVA++;
1742                 }
1743                 *newRDN++ = NULL;
1744                 tag = ber_next_element( ber, &len, dn_end );
1745         }
1746                 
1747         if ( func ) {
1748                 rc = func( newDN, flags, NULL );
1749                 if ( rc != LDAP_SUCCESS )
1750                         goto nomem;
1751         }
1752
1753         rc = ldap_dn2bv_x( newDN, bv, LDAP_DN_FORMAT_LDAPV3, NULL );
1754
1755 nomem:
1756         for (;baseAVA < newAVA; baseAVA++) {
1757                 if (baseAVA->la_flags & LDAP_AVA_FREE_ATTR)
1758                         LDAP_FREE( baseAVA->la_attr.bv_val );
1759                 if (baseAVA->la_flags & LDAP_AVA_FREE_VALUE)
1760                         LDAP_FREE( baseAVA->la_value.bv_val );
1761         }
1762
1763         if ( oidsize != 0 )
1764                 LDAP_FREE( oidbuf );
1765         if ( newDN != (LDAPDN)(char *) ptrs )
1766                 LDAP_FREE( newDN );
1767         return rc;
1768 }
1769
1770 #if 0
1771 /* test driver - feed in a DER cert on stdin */
1772 main( int argc, char *argv ) {
1773         char buf[8192];
1774         struct berval bv, bv2, dn;
1775         BerElementBuffer berbuf;
1776         BerElement *ber = (BerElement *)&berbuf;
1777         ber_tag_t tag;
1778         ber_len_t len;
1779
1780         bv.bv_len = fread(buf, 1, sizeof(buf), stdin);
1781         bv.bv_val = buf;
1782
1783         ber_init2( ber, &bv, LBER_USE_DER );
1784         tag = ber_skip_tag( ber, &len );        /* Sequence */
1785         tag = ber_skip_tag( ber, &len );        /* Sequence */
1786         tag = ber_skip_tag( ber, &len );        /* Context + Constructed (version) */
1787         if ( tag == 0xa0 )      /* Version is optional */
1788                 tag = ber_get_int( ber, &len ); /* Int: Version */
1789         tag = ber_get_int( ber, &len ); /* Int: Serial */
1790         tag = ber_skip_tag( ber, &len );        /* Sequence: Signature */
1791         tag = ber_skip_tag( ber, &len );        /* : Signature */
1792         ber_skip_data( ber, len );
1793         tag = ber_skip_tag( ber, &len );        /* : Signature */
1794         ber_skip_data( ber, len );
1795         tag = ber_peek_tag( ber, &len );        /* Sequence: Issuer DN */
1796         len = ber_ptrlen( ber );
1797         bv2.bv_val = bv.bv_val + len;
1798         bv2.bv_len = bv.bv_len - len;
1799         X509dn2bv( &bv2, &dn, NULL, 0 );
1800         printf( "Issuer: %s\n", dn.bv_val );
1801 }
1802 #endif
1803
1804 #endif /* HAVE_GNUTLS */