tls.c 70 KB
Newer Older
1
/* tls.c - Handle tls/ssl using SSLeay, OpenSSL or GNUTLS. */
2
/* $OpenLDAP$ */
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
4
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1998-2008 The OpenLDAP Foundation.
6
7
8
9
10
11
12
13
14
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
15
 */
16
17
18
19
/* ACKNOWLEDGEMENTS: GNUTLS support written by Howard Chu and
 * Matt Backes; sponsored by The Written Word (thewrittenword.com)
 * and Stanford University (stanford.edu).
 */
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
20
21

#include "portable.h"
22
#include "ldap_config.h"
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
23
24
25

#include <stdio.h>

26
#include <ac/stdlib.h>
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
27
28
29
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
Pierangelo Masarati's avatar
Pierangelo Masarati committed
30
#include <ac/ctype.h>
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
31
32
#include <ac/time.h>
#include <ac/unistd.h>
33
#include <ac/param.h>
34
#include <ac/dirent.h>
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
35
36
37

#include "ldap-int.h"

38
39
#ifdef HAVE_TLS

Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
40
41
42
43
#ifdef LDAP_R_COMPILE
#include <ldap_pvt_thread.h>
#endif

44
45
46
47
48
49
50
51
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gcrypt.h>

#define DH_BITS	(1024)

#else
52
53
#ifdef HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
54
55
#include <openssl/x509v3.h>
#include <openssl/err.h>
56
#include <openssl/rand.h>
57
#include <openssl/safestack.h>
58
#elif defined( HAVE_SSL_H )
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
59
60
#include <ssl.h>
#endif
61
#endif
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
62

63
#define HAS_TLS( sb )	ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \
64
				(void *)&sb_tls_sbio )
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#endif /* HAVE_TLS */

/* RFC2459 minimum required set of supported attribute types
 * in a certificate DN
 */
typedef struct oid_name {
	struct berval oid;
	struct berval name;
} oid_name;

#define	CN_OID	oids[0].oid.bv_val

static oid_name oids[] = {
	{ BER_BVC("2.5.4.3"), BER_BVC("cn") },
	{ BER_BVC("2.5.4.4"), BER_BVC("sn") },
	{ BER_BVC("2.5.4.6"), BER_BVC("c") },
	{ BER_BVC("2.5.4.7"), BER_BVC("l") },
	{ BER_BVC("2.5.4.8"), BER_BVC("st") },
	{ BER_BVC("2.5.4.10"), BER_BVC("o") },
	{ BER_BVC("2.5.4.11"), BER_BVC("ou") },
	{ BER_BVC("2.5.4.12"), BER_BVC("title") },
	{ BER_BVC("2.5.4.41"), BER_BVC("name") },
	{ BER_BVC("2.5.4.42"), BER_BVC("givenName") },
	{ BER_BVC("2.5.4.43"), BER_BVC("initials") },
	{ BER_BVC("2.5.4.44"), BER_BVC("generationQualifier") },
	{ BER_BVC("2.5.4.46"), BER_BVC("dnQualifier") },
	{ BER_BVC("1.2.840.113549.1.9.1"), BER_BVC("email") },
	{ BER_BVC("0.9.2342.19200300.100.1.25"), BER_BVC("dc") },
	{ BER_BVNULL, BER_BVNULL }
};

#ifdef HAVE_TLS
#ifdef HAVE_GNUTLS

typedef struct tls_cipher_suite {
	const char *name;
	gnutls_kx_algorithm_t kx;
	gnutls_cipher_algorithm_t cipher;
	gnutls_mac_algorithm_t mac;
	gnutls_protocol_t version;
} tls_cipher_suite;

static tls_cipher_suite *ciphers;
static int n_ciphers;

/* sorta replacing SSL_CTX */
typedef struct tls_ctx {
	struct ldapoptions *lo;
	gnutls_certificate_credentials_t cred;
	gnutls_dh_params_t dh_params;
	unsigned long verify_depth;
	int refcount;
	int *kx_list;
	int *cipher_list;
	int *mac_list;
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_t ref_mutex;
#endif
} tls_ctx;

/* sorta replacing SSL */
typedef struct tls_session {
	tls_ctx *ctx;
	gnutls_session_t session;
	struct berval peer_der_dn;
} tls_session;

#ifdef LDAP_R_COMPILE

static int
ldap_pvt_gcry_mutex_init( void **priv )
{
	int err = 0;
	ldap_pvt_thread_mutex_t *lock = LDAP_MALLOC( sizeof( ldap_pvt_thread_mutex_t ));

	if ( !lock )
		err = ENOMEM;
	if ( !err ) {
		err = ldap_pvt_thread_mutex_init( lock );
		if ( err )
			LDAP_FREE( lock );
		else
			*priv = lock;
	}
	return err;
}
static int
ldap_pvt_gcry_mutex_destroy( void **lock )
{
	int err = ldap_pvt_thread_mutex_destroy( *lock );
	LDAP_FREE( *lock );
	return err;
}
static int
ldap_pvt_gcry_mutex_lock( void **lock )
{
	return ldap_pvt_thread_mutex_lock( *lock );
}
static int
ldap_pvt_gcry_mutex_unlock( void **lock )
{
	return ldap_pvt_thread_mutex_unlock( *lock );
}

static struct gcry_thread_cbs ldap_generic_thread_cbs = {
	GCRY_THREAD_OPTION_USER,
	NULL,
	ldap_pvt_gcry_mutex_init,
	ldap_pvt_gcry_mutex_destroy,
	ldap_pvt_gcry_mutex_lock,
	ldap_pvt_gcry_mutex_unlock,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};

static void
tls_init_threads( void )
{
	gcry_control (GCRYCTL_SET_THREAD_CBS, &ldap_generic_thread_cbs);
}
#endif /* LDAP_R_COMPILE */

void
ldap_pvt_tls_ctx_free ( void *c )
{
	int refcount;
	tls_ctx *ctx = c;

	if ( !ctx ) return;

#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ctx->ref_mutex );
#endif
	refcount = --ctx->refcount;
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ctx->ref_mutex );
#endif
	if ( refcount )
		return;
	LDAP_FREE( ctx->kx_list );
	gnutls_certificate_free_credentials( ctx->cred );
	ber_memfree ( ctx );
}

static void *
tls_ctx_new ( struct ldapoptions *lo )
{
	tls_ctx *ctx;

	ctx = ber_memcalloc ( 1, sizeof (*ctx) );
	if ( ctx ) {
		ctx->lo = lo;
		if ( gnutls_certificate_allocate_credentials( &ctx->cred )) {
			ber_memfree( ctx );
			return NULL;
		}
		ctx->refcount = 1;
#ifdef LDAP_R_COMPILE
		ldap_pvt_thread_mutex_init( &ctx->ref_mutex );
#endif
	}
	return ctx;
}

static void
tls_ctx_ref( tls_ctx *ctx )
{
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &ctx->ref_mutex );
#endif
	ctx->refcount++;
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &ctx->ref_mutex );
#endif
}

tls_session *
tls_session_new ( tls_ctx * ctx, int is_server )
{
	tls_session *session;

	session = ber_memcalloc ( 1, sizeof (*session) );
	if ( !session )
		return NULL;

	session->ctx = ctx;
	gnutls_init( &session->session, is_server ? GNUTLS_SERVER : GNUTLS_CLIENT );
	gnutls_set_default_priority( session->session );
	if ( ctx->kx_list ) {
		gnutls_kx_set_priority( session->session, ctx->kx_list );
		gnutls_cipher_set_priority( session->session, ctx->cipher_list );
		gnutls_mac_set_priority( session->session, ctx->mac_list );
	}
	if ( ctx->cred )
		gnutls_credentials_set( session->session, GNUTLS_CRD_CERTIFICATE, ctx->cred );
	
	if ( is_server ) {
		int flag = 0;
		if ( ctx->lo->ldo_tls_require_cert ) {
			flag = GNUTLS_CERT_REQUEST;
			if ( ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND ||
				ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD )
				flag = GNUTLS_CERT_REQUIRE;
			gnutls_certificate_server_set_request( session->session, flag );
		}
	}
	return session;
} 

void
tls_session_free ( tls_session * session )
{
	ber_memfree ( session );
}

#define	tls_session_connect( ssl )	gnutls_handshake( ssl->session )
#define	tls_session_accept( ssl )	gnutls_handshake( ssl->session )

/* suites is a string of colon-separated cipher suite names. */
static int
tls_parse_ciphers( tls_ctx *ctx, char *suites )
{
	char *ptr, *end;
	int i, j, len, num;
	int *list, nkx = 0, ncipher = 0, nmac = 0;
	int *kx, *cipher, *mac;

	num = 0;
	ptr = suites;
	do {
		end = strchr(ptr, ':');
		if ( end )
			len = end - ptr;
		else
			len = strlen(ptr);
		for (i=0; i<n_ciphers; i++) {
			if ( !strncasecmp( ciphers[i].name, ptr, len )) {
				num++;
				break;
			}
		}
		if ( i == n_ciphers ) {
			/* unrecognized cipher suite */
			return -1;
		}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
310
		ptr += len + 1;
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
	} while (end);

	/* Space for all 3 lists */
	list = LDAP_MALLOC( (num+1) * sizeof(int) * 3 );
	if ( !list )
		return -1;
	kx = list;
	cipher = kx+num+1;
	mac = cipher+num+1;

	ptr = suites;
	do {
		end = strchr(ptr, ':');
		if ( end )
			len = end - ptr;
		else
			len = strlen(ptr);
		for (i=0; i<n_ciphers; i++) {
			/* For each cipher suite, insert its algorithms into
			 * their respective priority lists. Make sure they
			 * only appear once in each list.
			 */
			if ( !strncasecmp( ciphers[i].name, ptr, len )) {
				for (j=0; j<nkx; j++)
					if ( kx[j] == ciphers[i].kx )
						break;
				if ( j == nkx )
					kx[nkx++] = ciphers[i].kx;
				for (j=0; j<ncipher; j++)
					if ( cipher[j] == ciphers[i].cipher )
						break;
				if ( j == ncipher ) 
					cipher[ncipher++] = ciphers[i].cipher;
				for (j=0; j<nmac; j++)
					if ( mac[j] == ciphers[i].mac )
						break;
				if ( j == nmac )
					mac[nmac++] = ciphers[i].mac;
				break;
			}
		}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
352
		ptr += len + 1;
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
	} while (end);
	kx[nkx] = 0;
	cipher[ncipher] = 0;
	mac[nmac] = 0;
	ctx->kx_list = kx;
	ctx->cipher_list = cipher;
	ctx->mac_list = mac;
	return 0;
}

#else /* OpenSSL */

typedef SSL_CTX tls_ctx;
typedef SSL tls_session;

static int  tls_opt_trace = 1;
static char *tls_opt_randfile = NULL;

371
static void tls_report_error( void );
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
372

Hallvard Furuseth's avatar
Hallvard Furuseth committed
373
static void tls_info_cb( const SSL *ssl, int where, int ret );
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
374
static int tls_verify_cb( int ok, X509_STORE_CTX *ctx );
375
static int tls_verify_ok( int ok, X509_STORE_CTX *ctx );
376
static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length );
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
377

378
379
static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length );

380
381
382
383
384
385
386
387
typedef struct dhplist {
	struct dhplist *next;
	int keylength;
	DH *param;
} dhplist;

static dhplist *dhparams;

388
389
static int tls_seed_PRNG( const char *randfile );

Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
390
391
392
393
394
395
396
397
398
#ifdef LDAP_R_COMPILE
/*
 * provide mutexes for the SSLeay library.
 */
static ldap_pvt_thread_mutex_t	tls_mutexes[CRYPTO_NUM_LOCKS];

static void tls_locking_cb( int mode, int type, const char *file, int line )
{
	if ( mode & CRYPTO_LOCK ) {
399
		ldap_pvt_thread_mutex_lock( &tls_mutexes[type] );
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
400
	} else {
401
		ldap_pvt_thread_mutex_unlock( &tls_mutexes[type] );
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
402
403
404
	}
}

405
406
407
408
409
static unsigned long tls_thread_self( void )
{
	/* FIXME: CRYPTO_set_id_callback only works when ldap_pvt_thread_t
	 * is an integral type that fits in an unsigned long
	 */
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
410

411
412
413
414
415
416
	/* force an error if the ldap_pvt_thread_t type is too large */
	enum { ok = sizeof( ldap_pvt_thread_t ) <= sizeof( unsigned long ) };
	typedef struct { int dummy: ok ? 1 : -1; } Check[ok ? 1 : -1];

	return (unsigned long) ldap_pvt_thread_self();
}
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
417
418
419
420
421
422

static void tls_init_threads( void )
{
	int i;

	for( i=0; i< CRYPTO_NUM_LOCKS ; i++ ) {
423
		ldap_pvt_thread_mutex_init( &tls_mutexes[i] );
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
424
425
	}
	CRYPTO_set_locking_callback( tls_locking_cb );
426
	CRYPTO_set_id_callback( tls_thread_self );
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
427
428
429
}
#endif /* LDAP_R_COMPILE */

430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
void
ldap_pvt_tls_ctx_free ( void *c )
{

	SSL_CTX_free( c );
}

static void *
tls_ctx_new( struct ldapoptions *lo )
{
	return SSL_CTX_new( SSLv23_method() );
}

static void
tls_ctx_ref( void *c )
{
	SSL_CTX *ctx = c;
	CRYPTO_add( &ctx->references, 1, CRYPTO_LOCK_SSL_CTX );
}

static tls_session *
tls_session_new( tls_ctx *ctx, int is_server )
{
	return SSL_new( ctx );
}

#define	tls_session_connect( ssl )	SSL_connect( ssl )
#define	tls_session_accept( ssl )	SSL_accept( ssl )

static STACK_OF(X509_NAME) *
get_ca_list( char * bundle, char * dir )
{
	STACK_OF(X509_NAME) *ca_list = NULL;

	if ( bundle ) {
		ca_list = SSL_load_client_CA_file( bundle );
	}
#if defined(HAVE_DIRENT_H) || defined(dirent)
	if ( dir ) {
		int freeit = 0;

		if ( !ca_list ) {
			ca_list = sk_X509_NAME_new_null();
			freeit = 1;
		}
		if ( !SSL_add_dir_cert_subjects_to_stack( ca_list, dir ) &&
			freeit ) {
			sk_X509_NAME_free( ca_list );
			ca_list = NULL;
		}
	}
#endif
	return ca_list;
}

#endif /* HAVE_GNUTLS */

#ifdef LDAP_R_COMPILE
/*
 * an extra mutex for the default ctx.
 */
static ldap_pvt_thread_mutex_t tls_def_ctx_mutex;
#endif

Howard Chu's avatar
Howard Chu committed
494
495
496
void
ldap_int_tls_destroy( struct ldapoptions *lo )
{
Howard Chu's avatar
Howard Chu committed
497
	if ( lo->ldo_tls_ctx ) {
498
		ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
Howard Chu's avatar
Howard Chu committed
499
500
		lo->ldo_tls_ctx = NULL;
	}
Howard Chu's avatar
Howard Chu committed
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525

	if ( lo->ldo_tls_certfile ) {
		LDAP_FREE( lo->ldo_tls_certfile );
		lo->ldo_tls_certfile = NULL;
	}
	if ( lo->ldo_tls_keyfile ) {
		LDAP_FREE( lo->ldo_tls_keyfile );
		lo->ldo_tls_keyfile = NULL;
	}
	if ( lo->ldo_tls_dhfile ) {
		LDAP_FREE( lo->ldo_tls_dhfile );
		lo->ldo_tls_dhfile = NULL;
	}
	if ( lo->ldo_tls_cacertfile ) {
		LDAP_FREE( lo->ldo_tls_cacertfile );
		lo->ldo_tls_cacertfile = NULL;
	}
	if ( lo->ldo_tls_cacertdir ) {
		LDAP_FREE( lo->ldo_tls_cacertdir );
		lo->ldo_tls_cacertdir = NULL;
	}
	if ( lo->ldo_tls_ciphersuite ) {
		LDAP_FREE( lo->ldo_tls_ciphersuite );
		lo->ldo_tls_ciphersuite = NULL;
	}
526
527
528
529
530
531
#ifdef HAVE_GNUTLS
	if ( lo->ldo_tls_crlfile ) {
		LDAP_FREE( lo->ldo_tls_crlfile );
		lo->ldo_tls_crlfile = NULL;
	}
#endif
Howard Chu's avatar
Howard Chu committed
532
533
}

534
535
536
537
538
539
/*
 * Tear down the TLS subsystem. Should only be called once.
 */
void
ldap_pvt_tls_destroy( void )
{
Howard Chu's avatar
Howard Chu committed
540
541
542
543
	struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   

	ldap_int_tls_destroy( lo );

544
545
546
547
548
549
#ifdef HAVE_GNUTLS
	LDAP_FREE( ciphers );
	ciphers = NULL;

	gnutls_global_deinit();
#else
550
	EVP_cleanup();
Howard Chu's avatar
Howard Chu committed
551
	ERR_remove_state(0);
552
	ERR_free_strings();
553
554
555
556
557

	if ( tls_opt_randfile ) {
		LDAP_FREE( tls_opt_randfile );
		tls_opt_randfile = NULL;
	}
558
#endif
559
560
}

Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
561
/*
562
 * Initialize TLS subsystem. Should be called only once.
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
563
564
565
566
567
568
 */
int
ldap_pvt_tls_init( void )
{
	static int tls_initialized = 0;

569
	if ( tls_initialized++ ) return 0;
570

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
#ifdef LDAP_R_COMPILE
	tls_init_threads();
	ldap_pvt_thread_mutex_init( &tls_def_ctx_mutex );
#endif

#ifdef HAVE_GNUTLS
	gnutls_global_init ();

	/* GNUtls cipher suite handling: The library ought to parse suite
	 * names for us, but it doesn't. It will return a list of suite names
	 * that it supports, so we can do parsing ourselves. It ought to tell
	 * us how long the list is, but it doesn't do that either, so we just
	 * have to count it manually...
	 */
	{
		int i = 0;
		tls_cipher_suite *ptr, tmp;
		char cs_id[2];

		while ( gnutls_cipher_suite_info( i, cs_id, &tmp.kx, &tmp.cipher,
			&tmp.mac, &tmp.version ))
			i++;
		n_ciphers = i;

		/* Store a copy */
		ciphers = LDAP_MALLOC(n_ciphers * sizeof(tls_cipher_suite));
		if ( !ciphers )
			return -1;
		for ( i=0; i<n_ciphers; i++ ) {
			ciphers[i].name = gnutls_cipher_suite_info( i, cs_id,
				&ciphers[i].kx, &ciphers[i].cipher, &ciphers[i].mac,
				&ciphers[i].version );
		}
	}

#else /* !HAVE_GNUTLS */

Howard Chu's avatar
Howard Chu committed
608
609
610
611
612
613
614
615
#ifdef HAVE_EBCDIC
	{
		char *file = LDAP_STRDUP( tls_opt_randfile );
		if ( file ) __atoe( file );
		(void) tls_seed_PRNG( file );
		LDAP_FREE( file );
	}
#else
616
	(void) tls_seed_PRNG( tls_opt_randfile );
Howard Chu's avatar
Howard Chu committed
617
#endif
618

Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
619
620
	SSL_load_error_strings();
	SSLeay_add_ssl_algorithms();
621

622
623
	/* FIXME: mod_ssl does this */
	X509V3_add_standard_extensions();
624
625

#endif /* HAVE_GNUTLS */
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
626
627
628
629
	return 0;
}

/*
Howard Chu's avatar
Howard Chu committed
630
 * initialize a new TLS context
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
631
 */
Howard Chu's avatar
Howard Chu committed
632
633
static int
ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server )
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
634
{
Howard Chu's avatar
Howard Chu committed
635
636
637
638
639
640
	int i, rc = 0;
	char *ciphersuite = lo->ldo_tls_ciphersuite;
	char *cacertfile = lo->ldo_tls_cacertfile;
	char *cacertdir = lo->ldo_tls_cacertdir;
	char *certfile = lo->ldo_tls_certfile;
	char *keyfile = lo->ldo_tls_keyfile;
641
642
643
#ifdef HAVE_GNUTLS
	char *crlfile = lo->ldo_tls_crlfile;
#else
Howard Chu's avatar
Howard Chu committed
644
	char *dhfile = lo->ldo_tls_dhfile;
645
#endif
Howard Chu's avatar
Howard Chu committed
646
647
648

	if ( lo->ldo_tls_ctx )
		return 0;
649

650
651
	ldap_pvt_tls_init();

652
	if ( is_server && !certfile && !keyfile && !cacertfile && !cacertdir ) {
653
		/* minimum configuration not provided */
654
		return LDAP_NOT_SUPPORTED;
655
	}
656

Howard Chu's avatar
Howard Chu committed
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
#ifdef HAVE_EBCDIC
	/* This ASCII/EBCDIC handling is a real pain! */
	if ( ciphersuite ) {
		ciphersuite = LDAP_STRDUP( ciphersuite );
		__atoe( ciphersuite );
	}
	if ( cacertfile ) {
		cacertfile = LDAP_STRDUP( cacertfile );
		__atoe( cacertfile );
	}
	if ( certfile ) {
		certfile = LDAP_STRDUP( certfile );
		__atoe( certfile );
	}
	if ( keyfile ) {
		keyfile = LDAP_STRDUP( keyfile );
		__atoe( keyfile );
	}
675
676
677
678
679
680
681
682
683
684
#ifdef HAVE_GNUTLS
	if ( crlfile ) {
		crlfile = LDAP_STRDUP( crlfile );
		__atoe( crlfile );
	}
#else
	if ( cacertdir ) {
		cacertdir = LDAP_STRDUP( cacertdir );
		__atoe( cacertdir );
	}
685
686
687
688
	if ( dhfile ) {
		dhfile = LDAP_STRDUP( dhfile );
		__atoe( dhfile );
	}
Howard Chu's avatar
Howard Chu committed
689
#endif
690
691
#endif
	lo->ldo_tls_ctx = tls_ctx_new( lo );
Howard Chu's avatar
Howard Chu committed
692
	if ( lo->ldo_tls_ctx == NULL ) {
693
694
695
696
697
#ifdef HAVE_GNUTLS
		Debug( LDAP_DEBUG_ANY,
		   "TLS: could not allocate default ctx.\n",
			0,0,0);
#else
Howard Chu's avatar
Howard Chu committed
698
699
700
		Debug( LDAP_DEBUG_ANY,
		   "TLS: could not allocate default ctx (%lu).\n",
			ERR_peek_error(),0,0);
701
#endif
Howard Chu's avatar
Howard Chu committed
702
703
704
		rc = -1;
		goto error_exit;
	}
705

706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
#ifdef HAVE_GNUTLS
 	if ( lo->ldo_tls_ciphersuite &&
		tls_parse_ciphers( lo->ldo_tls_ctx,
			ciphersuite )) {
 		Debug( LDAP_DEBUG_ANY,
 			   "TLS: could not set cipher list %s.\n",
 			   lo->ldo_tls_ciphersuite, 0, 0 );
 		rc = -1;
 		goto error_exit;
 	}

	if (lo->ldo_tls_cacertdir != NULL) {
		Debug( LDAP_DEBUG_ANY, 
		       "TLS: warning: cacertdir not implemented for gnutls\n",
		       NULL, NULL, NULL );
	}

	if (lo->ldo_tls_cacertfile != NULL) {
		rc = gnutls_certificate_set_x509_trust_file( 
			((tls_ctx*) lo->ldo_tls_ctx)->cred,
			cacertfile,
			GNUTLS_X509_FMT_PEM );
		if ( rc < 0 ) goto error_exit;
	}

	if ( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) {
		rc = gnutls_certificate_set_x509_key_file( 
			((tls_ctx*) lo->ldo_tls_ctx)->cred,
			certfile,
			keyfile,
			GNUTLS_X509_FMT_PEM );
		if ( rc ) goto error_exit;
	} else if ( lo->ldo_tls_certfile || lo->ldo_tls_keyfile ) {
		Debug( LDAP_DEBUG_ANY, 
		       "TLS: only one of certfile and keyfile specified\n",
		       NULL, NULL, NULL );
		rc = 1;
		goto error_exit;
	}

	if ( lo->ldo_tls_dhfile ) {
		Debug( LDAP_DEBUG_ANY, 
		       "TLS: warning: ignoring dhfile\n", 
		       NULL, NULL, NULL );
	}

	if ( lo->ldo_tls_crlfile ) {
		rc = gnutls_certificate_set_x509_crl_file( 
			((tls_ctx*) lo->ldo_tls_ctx)->cred,
			crlfile,
			GNUTLS_X509_FMT_PEM );
		if ( rc < 0 ) goto error_exit;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
758
		rc = 0;
759
760
761
762
763
764
765
766
767
768
769
	}
	if ( is_server ) {
		gnutls_dh_params_init (&((tls_ctx*) 
					lo->ldo_tls_ctx)->dh_params);
		gnutls_dh_params_generate2 (((tls_ctx*) 
						 lo->ldo_tls_ctx)->dh_params, 
						DH_BITS);
	}

#else /* !HAVE_GNUTLS */

Howard Chu's avatar
Howard Chu committed
770
771
	if ( is_server ) {
		SSL_CTX_set_session_id_context( lo->ldo_tls_ctx,
772
			(const unsigned char *) "OpenLDAP", sizeof("OpenLDAP")-1 );
Howard Chu's avatar
Howard Chu committed
773
774
775
776
777
778
779
780
781
782
783
784
	}

	if ( lo->ldo_tls_ciphersuite &&
		!SSL_CTX_set_cipher_list( lo->ldo_tls_ctx, ciphersuite ) )
	{
		Debug( LDAP_DEBUG_ANY,
			   "TLS: could not set cipher list %s.\n",
			   lo->ldo_tls_ciphersuite, 0, 0 );
		tls_report_error();
		rc = -1;
		goto error_exit;
	}
Howard Chu's avatar
Howard Chu committed
785

Howard Chu's avatar
Howard Chu committed
786
787
788
789
	if (lo->ldo_tls_cacertfile != NULL || lo->ldo_tls_cacertdir != NULL) {
		if ( !SSL_CTX_load_verify_locations( lo->ldo_tls_ctx,
				cacertfile, cacertdir ) ||
			!SSL_CTX_set_default_verify_paths( lo->ldo_tls_ctx ) )
790
		{
Howard Chu's avatar
Howard Chu committed
791
792
793
794
795
			Debug( LDAP_DEBUG_ANY, "TLS: "
				"could not load verify locations (file:`%s',dir:`%s').\n",
				lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "",
				lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "",
				0 );
796
			tls_report_error();
Howard Chu's avatar
Howard Chu committed
797
			rc = -1;
798
799
			goto error_exit;
		}
800

Howard Chu's avatar
Howard Chu committed
801
		if ( is_server ) {
802
			STACK_OF(X509_NAME) *calist;
Howard Chu's avatar
Howard Chu committed
803
			/* List of CA names to send to a client */
Howard Chu's avatar
Howard Chu committed
804
			calist = get_ca_list( cacertfile, cacertdir );
805
			if ( !calist ) {
806
				Debug( LDAP_DEBUG_ANY, "TLS: "
Pierangelo Masarati's avatar
Pierangelo Masarati committed
807
					"could not load client CA list (file:`%s',dir:`%s').\n",
Howard Chu's avatar
Howard Chu committed
808
809
					lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "",
					lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "",
810
					0 );
811
				tls_report_error();
Howard Chu's avatar
Howard Chu committed
812
				rc = -1;
813
814
				goto error_exit;
			}
815

Howard Chu's avatar
Howard Chu committed
816
			SSL_CTX_set_client_CA_list( lo->ldo_tls_ctx, calist );
817
		}
Howard Chu's avatar
Howard Chu committed
818
	}
819

Howard Chu's avatar
Howard Chu committed
820
821
822
823
824
825
826
827
828
829
830
	if ( lo->ldo_tls_certfile &&
		!SSL_CTX_use_certificate_file( lo->ldo_tls_ctx,
			certfile, SSL_FILETYPE_PEM ) )
	{
		Debug( LDAP_DEBUG_ANY,
			"TLS: could not use certificate `%s'.\n",
			lo->ldo_tls_certfile,0,0);
		tls_report_error();
		rc = -1;
		goto error_exit;
	}
831

Howard Chu's avatar
Howard Chu committed
832
833
834
835
836
837
838
839
840
841
842
843
	/* Key validity is checked automatically if cert has already been set */
	if ( lo->ldo_tls_keyfile &&
		!SSL_CTX_use_PrivateKey_file( lo->ldo_tls_ctx,
			keyfile, SSL_FILETYPE_PEM ) )
	{
		Debug( LDAP_DEBUG_ANY,
			"TLS: could not use key file `%s'.\n",
			lo->ldo_tls_keyfile,0,0);
		tls_report_error();
		rc = -1;
		goto error_exit;
	}
844

Howard Chu's avatar
Howard Chu committed
845
846
847
848
849
850
	if ( lo->ldo_tls_dhfile ) {
		DH *dh = NULL;
		BIO *bio;
		dhplist *p;

		if (( bio=BIO_new_file( dhfile,"r" )) == NULL ) {
851
			Debug( LDAP_DEBUG_ANY,
Howard Chu's avatar
Howard Chu committed
852
853
				"TLS: could not use DH parameters file `%s'.\n",
				lo->ldo_tls_dhfile,0,0);
854
			tls_report_error();
Howard Chu's avatar
Howard Chu committed
855
			rc = -1;
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
856
857
			goto error_exit;
		}
Howard Chu's avatar
Howard Chu committed
858
859
860
861
862
863
864
		while (( dh=PEM_read_bio_DHparams( bio, NULL, NULL, NULL ))) {
			p = LDAP_MALLOC( sizeof(dhplist) );
			if ( p != NULL ) {
				p->keylength = DH_size( dh ) * 8;
				p->param = dh;
				p->next = dhparams;
				dhparams = p;
865
866
			}
		}
Howard Chu's avatar
Howard Chu committed
867
868
		BIO_free( bio );
	}
869

Howard Chu's avatar
Howard Chu committed
870
871
872
	if ( tls_opt_trace ) {
		SSL_CTX_set_info_callback( (SSL_CTX *)lo->ldo_tls_ctx, tls_info_cb );
	}
873

Howard Chu's avatar
Howard Chu committed
874
875
876
877
878
879
	i = SSL_VERIFY_NONE;
	if ( lo->ldo_tls_require_cert ) {
		i = SSL_VERIFY_PEER;
		if ( lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND ||
			 lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD ) {
			i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
880
		}
Howard Chu's avatar
Howard Chu committed
881
	}
882

Howard Chu's avatar
Howard Chu committed
883
884
885
886
887
888
889
	SSL_CTX_set_verify( lo->ldo_tls_ctx, i,
		lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW ?
		tls_verify_ok : tls_verify_cb );
	SSL_CTX_set_tmp_rsa_callback( lo->ldo_tls_ctx, tls_tmp_rsa_cb );
	if ( lo->ldo_tls_dhfile ) {
		SSL_CTX_set_tmp_dh_callback( lo->ldo_tls_ctx, tls_tmp_dh_cb );
	}
890
#ifdef HAVE_OPENSSL_CRL
Howard Chu's avatar
Howard Chu committed
891
892
893
894
895
896
897
	if ( lo->ldo_tls_crlcheck ) {
		X509_STORE *x509_s = SSL_CTX_get_cert_store( lo->ldo_tls_ctx );
		if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_PEER ) {
			X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK );
		} else if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_ALL ) {
			X509_STORE_set_flags( x509_s, 
					X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL  );
898
		}
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
899
	}
Howard Chu's avatar
Howard Chu committed
900
901
#endif

902
903
#endif /* HAVE_GNUTLS */

Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
904
error_exit:
Howard Chu's avatar
Howard Chu committed
905
	if ( rc == -1 && lo->ldo_tls_ctx != NULL ) {
906
		ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
Howard Chu's avatar
Howard Chu committed
907
		lo->ldo_tls_ctx = NULL;
908
	}
Howard Chu's avatar
Howard Chu committed
909
910
911
912
913
#ifdef HAVE_EBCDIC
	LDAP_FREE( ciphersuite );
	LDAP_FREE( cacertfile );
	LDAP_FREE( certfile );
	LDAP_FREE( keyfile );
914
915
916
917
#ifdef HAVE_GNUTLS
	LDAP_FREE( crlfile );
#else
	LDAP_FREE( cacertdir );
918
	LDAP_FREE( dhfile );
919
#endif
Howard Chu's avatar
Howard Chu committed
920
#endif
Howard Chu's avatar
Howard Chu committed
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
	return rc;
}

/*
 * initialize the default context
 */
int
ldap_pvt_tls_init_def_ctx( int is_server )
{
	struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
	int rc;
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_lock( &tls_def_ctx_mutex );
#endif
	rc = ldap_int_tls_init_ctx( lo, is_server );
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
936
937
938
#ifdef LDAP_R_COMPILE
	ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex );
#endif
Howard Chu's avatar
Howard Chu committed
939
	return rc;
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
940
941
}

942
static tls_session *
943
alloc_handle( void *ctx_arg, int is_server )
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
944
{
945
946
	tls_ctx	*ctx;
	tls_session	*ssl;
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
947
948

	if ( ctx_arg ) {
949
		ctx = ctx_arg;
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
950
	} else {
Howard Chu's avatar
Howard Chu committed
951
		struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
952
		if ( ldap_pvt_tls_init_def_ctx( is_server ) < 0 ) return NULL;
Howard Chu's avatar
Howard Chu committed
953
		ctx = lo->ldo_tls_ctx;
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
954
955
	}

956
	ssl = tls_session_new( ctx, is_server );
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
957
958
959
960
961
962
963
	if ( ssl == NULL ) {
		Debug( LDAP_DEBUG_ANY,"TLS: can't create ssl handle.\n",0,0,0);
		return NULL;
	}
	return ssl;
}

964
static int
965
update_flags( Sockbuf *sb, tls_session * ssl, int rc )
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
966
{
967
968
	sb->sb_trans_needs_read  = 0;
	sb->sb_trans_needs_write = 0;
969

970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
#ifdef HAVE_GNUTLS
	if ( rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN )
		return 0;

	switch (gnutls_record_get_direction (ssl->session)) {
	case 0: 
		sb->sb_trans_needs_read = 1;
		return 1;
	case 1:
		sb->sb_trans_needs_write = 1;
		return 1;
	}
#else /* !HAVE_GNUTLS */
	rc = SSL_get_error(ssl, rc);
	if (rc == SSL_ERROR_WANT_READ) {
985
986
987
		sb->sb_trans_needs_read  = 1;
		return 1;

988
	} else if (rc == SSL_ERROR_WANT_WRITE) {
989
990
991
		sb->sb_trans_needs_write = 1;
		return 1;

992
	} else if (rc == SSL_ERROR_WANT_CONNECT) {
993
		return 1;
994
	}
995
#endif /* HAVE_GNUTLS */
996
	return 0;
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
997
998
}

999
1000
/*
 * TLS support for LBER Sockbufs
For faster browsing, not all history is shown. View entire blame