1/*	$NetBSD$	*/
2
3/* tls.c - Handle tls/ssl. */
4/* OpenLDAP: pkg/ldap/libraries/libldap/tls2.c,v 1.4.2.10 2010/04/13 20:23:00 kurt Exp */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1998-2010 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18/* ACKNOWLEDGEMENTS: restructured by Howard Chu.
19 */
20
21#include "portable.h"
22#include "ldap_config.h"
23
24#include <stdio.h>
25
26#include <ac/stdlib.h>
27#include <ac/errno.h>
28#include <ac/socket.h>
29#include <ac/string.h>
30#include <ac/ctype.h>
31#include <ac/time.h>
32#include <ac/unistd.h>
33#include <ac/param.h>
34#include <ac/dirent.h>
35
36#include "ldap-int.h"
37
38#ifdef HAVE_TLS
39
40#include "ldap-tls.h"
41
42#ifdef LDAP_R_COMPILE
43#include <ldap_pvt_thread.h>
44#endif
45
46static tls_impl *tls_imp = &ldap_int_tls_impl;
47#define HAS_TLS( sb )	ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \
48				(void *)tls_imp->ti_sbio )
49
50#endif /* HAVE_TLS */
51
52/* RFC2459 minimum required set of supported attribute types
53 * in a certificate DN
54 */
55typedef struct oid_name {
56	struct berval oid;
57	struct berval name;
58} oid_name;
59
60static oid_name oids[] = {
61	{ BER_BVC("2.5.4.3"), BER_BVC("cn") },
62	{ BER_BVC("2.5.4.4"), BER_BVC("sn") },
63	{ BER_BVC("2.5.4.6"), BER_BVC("c") },
64	{ BER_BVC("2.5.4.7"), BER_BVC("l") },
65	{ BER_BVC("2.5.4.8"), BER_BVC("st") },
66	{ BER_BVC("2.5.4.10"), BER_BVC("o") },
67	{ BER_BVC("2.5.4.11"), BER_BVC("ou") },
68	{ BER_BVC("2.5.4.12"), BER_BVC("title") },
69	{ BER_BVC("2.5.4.41"), BER_BVC("name") },
70	{ BER_BVC("2.5.4.42"), BER_BVC("givenName") },
71	{ BER_BVC("2.5.4.43"), BER_BVC("initials") },
72	{ BER_BVC("2.5.4.44"), BER_BVC("generationQualifier") },
73	{ BER_BVC("2.5.4.46"), BER_BVC("dnQualifier") },
74	{ BER_BVC("1.2.840.113549.1.9.1"), BER_BVC("email") },
75	{ BER_BVC("0.9.2342.19200300.100.1.25"), BER_BVC("dc") },
76	{ BER_BVNULL, BER_BVNULL }
77};
78
79#ifdef HAVE_TLS
80
81void
82ldap_pvt_tls_ctx_free ( void *c )
83{
84	if ( !c ) return;
85	tls_imp->ti_ctx_free( c );
86}
87
88static void
89tls_ctx_ref( tls_ctx *ctx )
90{
91	if ( !ctx ) return;
92
93	tls_imp->ti_ctx_ref( ctx );
94}
95
96#ifdef LDAP_R_COMPILE
97/*
98 * an extra mutex for the default ctx.
99 */
100static ldap_pvt_thread_mutex_t tls_def_ctx_mutex;
101#endif
102
103void
104ldap_int_tls_destroy( struct ldapoptions *lo )
105{
106	if ( lo->ldo_tls_ctx ) {
107		ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
108		lo->ldo_tls_ctx = NULL;
109	}
110
111	if ( lo->ldo_tls_certfile ) {
112		LDAP_FREE( lo->ldo_tls_certfile );
113		lo->ldo_tls_certfile = NULL;
114	}
115	if ( lo->ldo_tls_keyfile ) {
116		LDAP_FREE( lo->ldo_tls_keyfile );
117		lo->ldo_tls_keyfile = NULL;
118	}
119	if ( lo->ldo_tls_dhfile ) {
120		LDAP_FREE( lo->ldo_tls_dhfile );
121		lo->ldo_tls_dhfile = NULL;
122	}
123	if ( lo->ldo_tls_cacertfile ) {
124		LDAP_FREE( lo->ldo_tls_cacertfile );
125		lo->ldo_tls_cacertfile = NULL;
126	}
127	if ( lo->ldo_tls_cacertdir ) {
128		LDAP_FREE( lo->ldo_tls_cacertdir );
129		lo->ldo_tls_cacertdir = NULL;
130	}
131	if ( lo->ldo_tls_ciphersuite ) {
132		LDAP_FREE( lo->ldo_tls_ciphersuite );
133		lo->ldo_tls_ciphersuite = NULL;
134	}
135	if ( lo->ldo_tls_crlfile ) {
136		LDAP_FREE( lo->ldo_tls_crlfile );
137		lo->ldo_tls_crlfile = NULL;
138	}
139}
140
141/*
142 * Tear down the TLS subsystem. Should only be called once.
143 */
144void
145ldap_pvt_tls_destroy( void )
146{
147	struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();
148
149	ldap_int_tls_destroy( lo );
150
151	tls_imp->ti_tls_destroy();
152}
153
154/*
155 * Initialize a particular TLS implementation.
156 * Called once per implementation.
157 */
158static int
159tls_init(tls_impl *impl )
160{
161	static int tls_initialized = 0;
162
163	if ( !tls_initialized++ ) {
164#ifdef LDAP_R_COMPILE
165		ldap_pvt_thread_mutex_init( &tls_def_ctx_mutex );
166#endif
167	}
168
169	if ( impl->ti_inited++ ) return 0;
170
171#ifdef LDAP_R_COMPILE
172	impl->ti_thr_init();
173#endif
174	return impl->ti_tls_init();
175}
176
177/*
178 * Initialize TLS subsystem. Called once per implementation.
179 */
180int
181ldap_pvt_tls_init( void )
182{
183	return tls_init( tls_imp );
184}
185
186/*
187 * initialize a new TLS context
188 */
189static int
190ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server )
191{
192	int rc = 0;
193	tls_impl *ti = tls_imp;
194	struct ldaptls lts = lo->ldo_tls_info;
195
196	if ( lo->ldo_tls_ctx )
197		return 0;
198
199	tls_init( ti );
200
201	if ( is_server && !lts.lt_certfile && !lts.lt_keyfile &&
202		!lts.lt_cacertfile && !lts.lt_cacertdir ) {
203		/* minimum configuration not provided */
204		return LDAP_NOT_SUPPORTED;
205	}
206
207#ifdef HAVE_EBCDIC
208	/* This ASCII/EBCDIC handling is a real pain! */
209	if ( lts.lt_ciphersuite ) {
210		lts.lt_ciphersuite = LDAP_STRDUP( lts.lt_ciphersuite );
211		__atoe( lts.lt_ciphersuite );
212	}
213	if ( lts.lt_cacertfile ) {
214		lts.lt_cacertfile = LDAP_STRDUP( lts.lt_cacertfile );
215		__atoe( lts.lt_cacertfile );
216	}
217	if ( lts.lt_certfile ) {
218		lts.lt_certfile = LDAP_STRDUP( lts.lt_certfile );
219		__atoe( lts.lt_certfile );
220	}
221	if ( lts.lt_keyfile ) {
222		lts.lt_keyfile = LDAP_STRDUP( lts.lt_keyfile );
223		__atoe( lts.lt_keyfile );
224	}
225	if ( lts.lt_crlfile ) {
226		lts.lt_crlfile = LDAP_STRDUP( lts.lt_crlfile );
227		__atoe( lts.lt_crlfile );
228	}
229	if ( lts.lt_cacertdir ) {
230		lts.lt_cacertdir = LDAP_STRDUP( lts.lt_cacertdir );
231		__atoe( lts.lt_cacertdir );
232	}
233	if ( lts.lt_dhfile ) {
234		lts.lt_dhfile = LDAP_STRDUP( lts.lt_dhfile );
235		__atoe( lts.lt_dhfile );
236	}
237#endif
238	lo->ldo_tls_ctx = ti->ti_ctx_new( lo );
239	if ( lo->ldo_tls_ctx == NULL ) {
240		Debug( LDAP_DEBUG_ANY,
241		   "TLS: could not allocate default ctx.\n",
242			0,0,0);
243		rc = -1;
244		goto error_exit;
245	}
246
247	rc = ti->ti_ctx_init( lo, &lts, is_server );
248
249error_exit:
250	if ( rc < 0 && lo->ldo_tls_ctx != NULL ) {
251		ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
252		lo->ldo_tls_ctx = NULL;
253	}
254#ifdef HAVE_EBCDIC
255	LDAP_FREE( lts.lt_ciphersuite );
256	LDAP_FREE( lts.lt_cacertfile );
257	LDAP_FREE( lts.lt_certfile );
258	LDAP_FREE( lts.lt_keyfile );
259	LDAP_FREE( lts.lt_crlfile );
260	LDAP_FREE( lts.lt_cacertdir );
261	LDAP_FREE( lts.lt_dhfile );
262#endif
263	return rc;
264}
265
266/*
267 * initialize the default context
268 */
269int
270ldap_pvt_tls_init_def_ctx( int is_server )
271{
272	struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();
273	int rc;
274#ifdef LDAP_R_COMPILE
275	ldap_pvt_thread_mutex_lock( &tls_def_ctx_mutex );
276#endif
277	rc = ldap_int_tls_init_ctx( lo, is_server );
278#ifdef LDAP_R_COMPILE
279	ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex );
280#endif
281	return rc;
282}
283
284static tls_session *
285alloc_handle( void *ctx_arg, int is_server )
286{
287	tls_ctx	*ctx;
288	tls_session	*ssl;
289
290	if ( ctx_arg ) {
291		ctx = ctx_arg;
292	} else {
293		struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();
294		if ( ldap_pvt_tls_init_def_ctx( is_server ) < 0 ) return NULL;
295		ctx = lo->ldo_tls_ctx;
296	}
297
298	ssl = tls_imp->ti_session_new( ctx, is_server );
299	if ( ssl == NULL ) {
300		Debug( LDAP_DEBUG_ANY,"TLS: can't create ssl handle.\n",0,0,0);
301		return NULL;
302	}
303	return ssl;
304}
305
306static int
307update_flags( Sockbuf *sb, tls_session * ssl, int rc )
308{
309	sb->sb_trans_needs_read  = 0;
310	sb->sb_trans_needs_write = 0;
311
312	return tls_imp->ti_session_upflags( sb, ssl, rc );
313}
314
315/*
316 * Call this to do a TLS connect on a sockbuf. ctx_arg can be
317 * a SSL_CTX * or NULL, in which case the default ctx is used.
318 *
319 * Return value:
320 *
321 *  0 - Success. Connection is ready for communication.
322 * <0 - Error. Can't create a TLS stream.
323 * >0 - Partial success.
324 *	  Do a select (using information from lber_pvt_sb_needs_{read,write}
325 *		and call again.
326 */
327
328static int
329ldap_int_tls_connect( LDAP *ld, LDAPConn *conn )
330{
331	Sockbuf *sb = conn->lconn_sb;
332	int	err;
333	tls_session	*ssl = NULL;
334
335	if ( HAS_TLS( sb )) {
336		ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl );
337	} else {
338		struct ldapoptions *lo;
339		tls_ctx *ctx;
340
341		ctx = ld->ld_options.ldo_tls_ctx;
342
343		ssl = alloc_handle( ctx, 0 );
344
345		if ( ssl == NULL ) return -1;
346
347#ifdef LDAP_DEBUG
348		ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
349			LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
350#endif
351		ber_sockbuf_add_io( sb, tls_imp->ti_sbio,
352			LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );
353
354		lo = LDAP_INT_GLOBAL_OPT();
355		if( ctx == NULL ) {
356			ctx = lo->ldo_tls_ctx;
357			ld->ld_options.ldo_tls_ctx = ctx;
358			tls_ctx_ref( ctx );
359		}
360		if ( ld->ld_options.ldo_tls_connect_cb )
361			ld->ld_options.ldo_tls_connect_cb( ld, ssl, ctx,
362			ld->ld_options.ldo_tls_connect_arg );
363		if ( lo && lo->ldo_tls_connect_cb && lo->ldo_tls_connect_cb !=
364			ld->ld_options.ldo_tls_connect_cb )
365			lo->ldo_tls_connect_cb( ld, ssl, ctx, lo->ldo_tls_connect_arg );
366	}
367
368	err = tls_imp->ti_session_connect( ld, ssl );
369
370#ifdef HAVE_WINSOCK
371	errno = WSAGetLastError();
372#endif
373
374	if ( err < 0 )
375	{
376		char buf[256], *msg;
377		if ( update_flags( sb, ssl, err )) {
378			return 1;
379		}
380
381		msg = tls_imp->ti_session_errmsg( ssl, err, buf, sizeof(buf) );
382		if ( msg ) {
383			if ( ld->ld_error ) {
384				LDAP_FREE( ld->ld_error );
385			}
386			ld->ld_error = LDAP_STRDUP( msg );
387#ifdef HAVE_EBCDIC
388			if ( ld->ld_error ) __etoa(ld->ld_error);
389#endif
390		}
391
392		Debug( LDAP_DEBUG_ANY,"TLS: can't connect: %s.\n",
393			ld->ld_error ? ld->ld_error : "" ,0,0);
394
395		ber_sockbuf_remove_io( sb, tls_imp->ti_sbio,
396			LBER_SBIOD_LEVEL_TRANSPORT );
397#ifdef LDAP_DEBUG
398		ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
399			LBER_SBIOD_LEVEL_TRANSPORT );
400#endif
401		return -1;
402	}
403
404	return 0;
405}
406
407/*
408 * Call this to do a TLS accept on a sockbuf.
409 * Everything else is the same as with tls_connect.
410 */
411int
412ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg )
413{
414	int	err;
415	tls_session	*ssl = NULL;
416
417	if ( HAS_TLS( sb )) {
418		ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl );
419	} else {
420		ssl = alloc_handle( ctx_arg, 1 );
421		if ( ssl == NULL ) return -1;
422
423#ifdef LDAP_DEBUG
424		ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
425			LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
426#endif
427		ber_sockbuf_add_io( sb, tls_imp->ti_sbio,
428			LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );
429	}
430
431	err = tls_imp->ti_session_accept( ssl );
432
433#ifdef HAVE_WINSOCK
434	errno = WSAGetLastError();
435#endif
436
437	if ( err < 0 )
438	{
439		if ( update_flags( sb, ssl, err )) return 1;
440
441		if ( DebugTest( LDAP_DEBUG_ANY ) ) {
442			char buf[256], *msg;
443			msg = tls_imp->ti_session_errmsg( ssl, err, buf, sizeof(buf) );
444			Debug( LDAP_DEBUG_ANY,"TLS: can't accept: %s.\n",
445				msg ? msg : "(unknown)", 0, 0 );
446		}
447
448		ber_sockbuf_remove_io( sb, tls_imp->ti_sbio,
449			LBER_SBIOD_LEVEL_TRANSPORT );
450#ifdef LDAP_DEBUG
451		ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
452			LBER_SBIOD_LEVEL_TRANSPORT );
453#endif
454		return -1;
455	}
456	return 0;
457}
458
459int
460ldap_pvt_tls_inplace ( Sockbuf *sb )
461{
462	return HAS_TLS( sb ) ? 1 : 0;
463}
464
465int
466ldap_tls_inplace( LDAP *ld )
467{
468	Sockbuf		*sb = NULL;
469
470	if ( ld->ld_defconn && ld->ld_defconn->lconn_sb ) {
471		sb = ld->ld_defconn->lconn_sb;
472
473	} else if ( ld->ld_sb ) {
474		sb = ld->ld_sb;
475
476	} else {
477		return 0;
478	}
479
480	return ldap_pvt_tls_inplace( sb );
481}
482
483int
484ldap_pvt_tls_get_peer_dn( void *s, struct berval *dn,
485	LDAPDN_rewrite_dummy *func, unsigned flags )
486{
487	tls_session *session = s;
488	struct berval bvdn;
489	int rc;
490
491	rc = tls_imp->ti_session_peer_dn( session, &bvdn );
492	if ( rc ) return rc;
493
494	rc = ldap_X509dn2bv( &bvdn, dn,
495			    (LDAPDN_rewrite_func *)func, flags);
496	return rc;
497}
498
499int
500ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in )
501{
502	tls_session *session = s;
503
504	return tls_imp->ti_session_chkhost( ld, session, name_in );
505}
506
507int
508ldap_int_tls_config( LDAP *ld, int option, const char *arg )
509{
510	int i;
511
512	switch( option ) {
513	case LDAP_OPT_X_TLS_CACERTFILE:
514	case LDAP_OPT_X_TLS_CACERTDIR:
515	case LDAP_OPT_X_TLS_CERTFILE:
516	case LDAP_OPT_X_TLS_KEYFILE:
517	case LDAP_OPT_X_TLS_RANDOM_FILE:
518	case LDAP_OPT_X_TLS_CIPHER_SUITE:
519	case LDAP_OPT_X_TLS_DHFILE:
520	case LDAP_OPT_X_TLS_CRLFILE:	/* GnuTLS only */
521		return ldap_pvt_tls_set_option( ld, option, (void *) arg );
522
523	case LDAP_OPT_X_TLS_REQUIRE_CERT:
524	case LDAP_OPT_X_TLS:
525		i = -1;
526		if ( strcasecmp( arg, "never" ) == 0 ) {
527			i = LDAP_OPT_X_TLS_NEVER ;
528
529		} else if ( strcasecmp( arg, "demand" ) == 0 ) {
530			i = LDAP_OPT_X_TLS_DEMAND ;
531
532		} else if ( strcasecmp( arg, "allow" ) == 0 ) {
533			i = LDAP_OPT_X_TLS_ALLOW ;
534
535		} else if ( strcasecmp( arg, "try" ) == 0 ) {
536			i = LDAP_OPT_X_TLS_TRY ;
537
538		} else if ( ( strcasecmp( arg, "hard" ) == 0 ) ||
539			( strcasecmp( arg, "on" ) == 0 ) ||
540			( strcasecmp( arg, "yes" ) == 0) ||
541			( strcasecmp( arg, "true" ) == 0 ) )
542		{
543			i = LDAP_OPT_X_TLS_HARD ;
544		}
545
546		if (i >= 0) {
547			return ldap_pvt_tls_set_option( ld, option, &i );
548		}
549		return -1;
550	case LDAP_OPT_X_TLS_PROTOCOL_MIN: {
551		char *next;
552		long l;
553		l = strtol( arg, &next, 10 );
554		if ( l < 0 || l > 0xff || next == arg ||
555			( *next != '\0' && *next != '.' ) )
556			return -1;
557		i = l << 8;
558		if (*next == '.') {
559			arg = next + 1;
560			l = strtol( arg, &next, 10 );
561			if ( l < 0 || l > 0xff || next == arg || *next != '\0' )
562				return -1;
563			i += l;
564		}
565		return ldap_pvt_tls_set_option( ld, option, &i );
566		}
567#ifdef HAVE_OPENSSL_CRL
568	case LDAP_OPT_X_TLS_CRLCHECK:	/* OpenSSL only */
569		i = -1;
570		if ( strcasecmp( arg, "none" ) == 0 ) {
571			i = LDAP_OPT_X_TLS_CRL_NONE ;
572		} else if ( strcasecmp( arg, "peer" ) == 0 ) {
573			i = LDAP_OPT_X_TLS_CRL_PEER ;
574		} else if ( strcasecmp( arg, "all" ) == 0 ) {
575			i = LDAP_OPT_X_TLS_CRL_ALL ;
576		}
577		if (i >= 0) {
578			return ldap_pvt_tls_set_option( ld, option, &i );
579		}
580		return -1;
581#endif
582	}
583	return -1;
584}
585
586int
587ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg )
588{
589	struct ldapoptions *lo;
590
591	if( ld != NULL ) {
592		assert( LDAP_VALID( ld ) );
593
594		if( !LDAP_VALID( ld ) ) {
595			return LDAP_OPT_ERROR;
596		}
597
598		lo = &ld->ld_options;
599
600	} else {
601		/* Get pointer to global option structure */
602		lo = LDAP_INT_GLOBAL_OPT();
603		if ( lo == NULL ) {
604			return LDAP_NO_MEMORY;
605		}
606	}
607
608	switch( option ) {
609	case LDAP_OPT_X_TLS:
610		*(int *)arg = lo->ldo_tls_mode;
611		break;
612	case LDAP_OPT_X_TLS_CTX:
613		*(void **)arg = lo->ldo_tls_ctx;
614		if ( lo->ldo_tls_ctx ) {
615			tls_ctx_ref( lo->ldo_tls_ctx );
616		}
617		break;
618	case LDAP_OPT_X_TLS_CACERTFILE:
619		*(char **)arg = lo->ldo_tls_cacertfile ?
620			LDAP_STRDUP( lo->ldo_tls_cacertfile ) : NULL;
621		break;
622	case LDAP_OPT_X_TLS_CACERTDIR:
623		*(char **)arg = lo->ldo_tls_cacertdir ?
624			LDAP_STRDUP( lo->ldo_tls_cacertdir ) : NULL;
625		break;
626	case LDAP_OPT_X_TLS_CERTFILE:
627		*(char **)arg = lo->ldo_tls_certfile ?
628			LDAP_STRDUP( lo->ldo_tls_certfile ) : NULL;
629		break;
630	case LDAP_OPT_X_TLS_KEYFILE:
631		*(char **)arg = lo->ldo_tls_keyfile ?
632			LDAP_STRDUP( lo->ldo_tls_keyfile ) : NULL;
633		break;
634	case LDAP_OPT_X_TLS_DHFILE:
635		*(char **)arg = lo->ldo_tls_dhfile ?
636			LDAP_STRDUP( lo->ldo_tls_dhfile ) : NULL;
637		break;
638	case LDAP_OPT_X_TLS_CRLFILE:	/* GnuTLS only */
639		*(char **)arg = lo->ldo_tls_crlfile ?
640			LDAP_STRDUP( lo->ldo_tls_crlfile ) : NULL;
641		break;
642	case LDAP_OPT_X_TLS_REQUIRE_CERT:
643		*(int *)arg = lo->ldo_tls_require_cert;
644		break;
645#ifdef HAVE_OPENSSL_CRL
646	case LDAP_OPT_X_TLS_CRLCHECK:	/* OpenSSL only */
647		*(int *)arg = lo->ldo_tls_crlcheck;
648		break;
649#endif
650	case LDAP_OPT_X_TLS_CIPHER_SUITE:
651		*(char **)arg = lo->ldo_tls_ciphersuite ?
652			LDAP_STRDUP( lo->ldo_tls_ciphersuite ) : NULL;
653		break;
654	case LDAP_OPT_X_TLS_PROTOCOL_MIN:
655		*(int *)arg = lo->ldo_tls_protocol_min;
656		break;
657	case LDAP_OPT_X_TLS_RANDOM_FILE:
658		*(char **)arg = lo->ldo_tls_randfile ?
659			LDAP_STRDUP( lo->ldo_tls_randfile ) : NULL;
660		break;
661	case LDAP_OPT_X_TLS_SSL_CTX: {
662		void *retval = 0;
663		if ( ld != NULL ) {
664			LDAPConn *conn = ld->ld_defconn;
665			if ( conn != NULL ) {
666				Sockbuf *sb = conn->lconn_sb;
667				retval = ldap_pvt_tls_sb_ctx( sb );
668			}
669		}
670		*(void **)arg = retval;
671		break;
672	}
673	case LDAP_OPT_X_TLS_CONNECT_CB:
674		*(LDAP_TLS_CONNECT_CB **)arg = lo->ldo_tls_connect_cb;
675		break;
676	case LDAP_OPT_X_TLS_CONNECT_ARG:
677		*(void **)arg = lo->ldo_tls_connect_arg;
678		break;
679	default:
680		return -1;
681	}
682	return 0;
683}
684
685int
686ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
687{
688	struct ldapoptions *lo;
689
690	if( ld != NULL ) {
691		assert( LDAP_VALID( ld ) );
692
693		if( !LDAP_VALID( ld ) ) {
694			return LDAP_OPT_ERROR;
695		}
696
697		lo = &ld->ld_options;
698
699	} else {
700		/* Get pointer to global option structure */
701		lo = LDAP_INT_GLOBAL_OPT();
702		if ( lo == NULL ) {
703			return LDAP_NO_MEMORY;
704		}
705	}
706
707	switch( option ) {
708	case LDAP_OPT_X_TLS:
709		if ( !arg ) return -1;
710
711		switch( *(int *) arg ) {
712		case LDAP_OPT_X_TLS_NEVER:
713		case LDAP_OPT_X_TLS_DEMAND:
714		case LDAP_OPT_X_TLS_ALLOW:
715		case LDAP_OPT_X_TLS_TRY:
716		case LDAP_OPT_X_TLS_HARD:
717			if (lo != NULL) {
718				lo->ldo_tls_mode = *(int *)arg;
719			}
720
721			return 0;
722		}
723		return -1;
724
725	case LDAP_OPT_X_TLS_CTX:
726		if ( lo->ldo_tls_ctx )
727			ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
728		lo->ldo_tls_ctx = arg;
729		tls_ctx_ref( lo->ldo_tls_ctx );
730		return 0;
731	case LDAP_OPT_X_TLS_CONNECT_CB:
732		lo->ldo_tls_connect_cb = (LDAP_TLS_CONNECT_CB *)arg;
733		return 0;
734	case LDAP_OPT_X_TLS_CONNECT_ARG:
735		lo->ldo_tls_connect_arg = arg;
736		return 0;
737	case LDAP_OPT_X_TLS_CACERTFILE:
738		if ( lo->ldo_tls_cacertfile ) LDAP_FREE( lo->ldo_tls_cacertfile );
739		lo->ldo_tls_cacertfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
740		return 0;
741	case LDAP_OPT_X_TLS_CACERTDIR:
742		if ( lo->ldo_tls_cacertdir ) LDAP_FREE( lo->ldo_tls_cacertdir );
743		lo->ldo_tls_cacertdir = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
744		return 0;
745	case LDAP_OPT_X_TLS_CERTFILE:
746		if ( lo->ldo_tls_certfile ) LDAP_FREE( lo->ldo_tls_certfile );
747		lo->ldo_tls_certfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
748		return 0;
749	case LDAP_OPT_X_TLS_KEYFILE:
750		if ( lo->ldo_tls_keyfile ) LDAP_FREE( lo->ldo_tls_keyfile );
751		lo->ldo_tls_keyfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
752		return 0;
753	case LDAP_OPT_X_TLS_DHFILE:
754		if ( lo->ldo_tls_dhfile ) LDAP_FREE( lo->ldo_tls_dhfile );
755		lo->ldo_tls_dhfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
756		return 0;
757	case LDAP_OPT_X_TLS_CRLFILE:	/* GnuTLS only */
758		if ( lo->ldo_tls_crlfile ) LDAP_FREE( lo->ldo_tls_crlfile );
759		lo->ldo_tls_crlfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
760		return 0;
761	case LDAP_OPT_X_TLS_REQUIRE_CERT:
762		if ( !arg ) return -1;
763		switch( *(int *) arg ) {
764		case LDAP_OPT_X_TLS_NEVER:
765		case LDAP_OPT_X_TLS_DEMAND:
766		case LDAP_OPT_X_TLS_ALLOW:
767		case LDAP_OPT_X_TLS_TRY:
768		case LDAP_OPT_X_TLS_HARD:
769			lo->ldo_tls_require_cert = * (int *) arg;
770			return 0;
771		}
772		return -1;
773#ifdef HAVE_OPENSSL_CRL
774	case LDAP_OPT_X_TLS_CRLCHECK:	/* OpenSSL only */
775		if ( !arg ) return -1;
776		switch( *(int *) arg ) {
777		case LDAP_OPT_X_TLS_CRL_NONE:
778		case LDAP_OPT_X_TLS_CRL_PEER:
779		case LDAP_OPT_X_TLS_CRL_ALL:
780			lo->ldo_tls_crlcheck = * (int *) arg;
781			return 0;
782		}
783		return -1;
784#endif
785	case LDAP_OPT_X_TLS_CIPHER_SUITE:
786		if ( lo->ldo_tls_ciphersuite ) LDAP_FREE( lo->ldo_tls_ciphersuite );
787		lo->ldo_tls_ciphersuite = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
788		return 0;
789
790	case LDAP_OPT_X_TLS_PROTOCOL_MIN:
791		if ( !arg ) return -1;
792		lo->ldo_tls_protocol_min = *(int *)arg;
793		return 0;
794	case LDAP_OPT_X_TLS_RANDOM_FILE:
795		if ( ld != NULL )
796			return -1;
797		if ( lo->ldo_tls_randfile ) LDAP_FREE (lo->ldo_tls_randfile );
798		lo->ldo_tls_randfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
799		break;
800	case LDAP_OPT_X_TLS_NEWCTX:
801		if ( !arg ) return -1;
802		if ( lo->ldo_tls_ctx )
803			ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
804		lo->ldo_tls_ctx = NULL;
805		return ldap_int_tls_init_ctx( lo, *(int *)arg );
806	default:
807		return -1;
808	}
809	return 0;
810}
811
812int
813ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
814{
815	Sockbuf *sb = conn->lconn_sb;
816	char *host;
817	void *ssl;
818
819	if( srv ) {
820		host = srv->lud_host;
821	} else {
822 		host = conn->lconn_server->lud_host;
823	}
824
825	/* avoid NULL host */
826	if( host == NULL ) {
827		host = "localhost";
828	}
829
830	(void) tls_init( tls_imp );
831
832	/*
833	 * Fortunately, the lib uses blocking io...
834	 */
835	if ( ldap_int_tls_connect( ld, conn ) < 0 ) {
836		ld->ld_errno = LDAP_CONNECT_ERROR;
837		return (ld->ld_errno);
838	}
839
840	ssl = ldap_pvt_tls_sb_ctx( sb );
841	assert( ssl != NULL );
842
843	/*
844	 * compare host with name(s) in certificate
845	 */
846	if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER) {
847		ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host );
848		if (ld->ld_errno != LDAP_SUCCESS) {
849			return ld->ld_errno;
850		}
851	}
852
853	return LDAP_SUCCESS;
854}
855
856void *
857ldap_pvt_tls_sb_ctx( Sockbuf *sb )
858{
859	void			*p = NULL;
860
861	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p );
862	return p;
863}
864
865int
866ldap_pvt_tls_get_strength( void *s )
867{
868	tls_session *session = s;
869
870	return tls_imp->ti_session_strength( session );
871}
872
873int
874ldap_pvt_tls_get_my_dn( void *s, struct berval *dn, LDAPDN_rewrite_dummy *func, unsigned flags )
875{
876	tls_session *session = s;
877	struct berval der_dn;
878	int rc;
879
880	rc = tls_imp->ti_session_my_dn( session, &der_dn );
881	if ( rc == LDAP_SUCCESS )
882		rc = ldap_X509dn2bv(&der_dn, dn, (LDAPDN_rewrite_func *)func, flags );
883	return rc;
884}
885#endif /* HAVE_TLS */
886
887int
888ldap_start_tls( LDAP *ld,
889	LDAPControl **serverctrls,
890	LDAPControl **clientctrls,
891	int *msgidp )
892{
893	return ldap_extended_operation( ld, LDAP_EXOP_START_TLS,
894		NULL, serverctrls, clientctrls, msgidp );
895}
896
897int
898ldap_install_tls( LDAP *ld )
899{
900#ifndef HAVE_TLS
901	return LDAP_NOT_SUPPORTED;
902#else
903	if ( ldap_tls_inplace( ld ) ) {
904		return LDAP_LOCAL_ERROR;
905	}
906
907	return ldap_int_tls_start( ld, ld->ld_defconn, NULL );
908#endif
909}
910
911int
912ldap_start_tls_s ( LDAP *ld,
913	LDAPControl **serverctrls,
914	LDAPControl **clientctrls )
915{
916#ifndef HAVE_TLS
917	return LDAP_NOT_SUPPORTED;
918#else
919	int rc;
920	char *rspoid = NULL;
921	struct berval *rspdata = NULL;
922
923	/* XXYYZ: this initiates operation only on default connection! */
924
925	if ( ldap_tls_inplace( ld ) ) {
926		return LDAP_LOCAL_ERROR;
927	}
928
929	rc = ldap_extended_operation_s( ld, LDAP_EXOP_START_TLS,
930		NULL, serverctrls, clientctrls, &rspoid, &rspdata );
931
932	if ( rspoid != NULL ) {
933		LDAP_FREE(rspoid);
934	}
935
936	if ( rspdata != NULL ) {
937		ber_bvfree( rspdata );
938	}
939
940	if ( rc == LDAP_SUCCESS ) {
941		rc = ldap_int_tls_start( ld, ld->ld_defconn, NULL );
942	}
943
944	return rc;
945#endif
946}
947
948/* These tags probably all belong in lber.h, but they're
949 * not normally encountered when processing LDAP, so maybe
950 * they belong somewhere else instead.
951 */
952
953#define LBER_TAG_OID		((ber_tag_t) 0x06UL)
954
955/* Tags for string types used in a DirectoryString.
956 *
957 * Note that IA5string is not one of the defined choices for
958 * DirectoryString in X.520, but it gets used for email AVAs.
959 */
960#define	LBER_TAG_UTF8		((ber_tag_t) 0x0cUL)
961#define	LBER_TAG_PRINTABLE	((ber_tag_t) 0x13UL)
962#define	LBER_TAG_TELETEX	((ber_tag_t) 0x14UL)
963#define	LBER_TAG_IA5		((ber_tag_t) 0x16UL)
964#define	LBER_TAG_UNIVERSAL	((ber_tag_t) 0x1cUL)
965#define	LBER_TAG_BMP		((ber_tag_t) 0x1eUL)
966
967static oid_name *
968find_oid( struct berval *oid )
969{
970	int i;
971
972	for ( i=0; !BER_BVISNULL( &oids[i].oid ); i++ ) {
973		if ( oids[i].oid.bv_len != oid->bv_len ) continue;
974		if ( !strcmp( oids[i].oid.bv_val, oid->bv_val ))
975			return &oids[i];
976	}
977	return NULL;
978}
979
980/* Convert a structured DN from an X.509 certificate into an LDAPV3 DN.
981 * x509_name must be raw DER. If func is non-NULL, the
982 * constructed DN will use numeric OIDs to identify attributeTypes,
983 * and the func() will be invoked to rewrite the DN with the given
984 * flags.
985 *
986 * Otherwise the DN will use shortNames from a hardcoded table.
987 */
988int
989ldap_X509dn2bv( void *x509_name, struct berval *bv, LDAPDN_rewrite_func *func,
990	unsigned flags )
991{
992	LDAPDN	newDN;
993	LDAPRDN	newRDN;
994	LDAPAVA *newAVA, *baseAVA;
995	BerElementBuffer berbuf;
996	BerElement *ber = (BerElement *)&berbuf;
997	char oids[8192], *oidptr = oids, *oidbuf = NULL;
998	void *ptrs[2048];
999	char *dn_end, *rdn_end;
1000	int i, navas, nrdns, rc = LDAP_SUCCESS;
1001	size_t dnsize, oidrem = sizeof(oids), oidsize = 0;
1002	int csize;
1003	ber_tag_t tag;
1004	ber_len_t len;
1005	oid_name *oidname;
1006
1007	struct berval	Oid, Val, oid2, *in = x509_name;
1008
1009	assert( bv != NULL );
1010
1011	bv->bv_len = 0;
1012	bv->bv_val = NULL;
1013
1014	navas = 0;
1015	nrdns = 0;
1016
1017	/* A DN is a SEQUENCE of RDNs. An RDN is a SET of AVAs.
1018	 * An AVA is a SEQUENCE of attr and value.
1019	 * Count the number of AVAs and RDNs
1020	 */
1021	ber_init2( ber, in, LBER_USE_DER );
1022	tag = ber_peek_tag( ber, &len );
1023	if ( tag != LBER_SEQUENCE )
1024		return LDAP_DECODING_ERROR;
1025
1026	for ( tag = ber_first_element( ber, &len, &dn_end );
1027		tag == LBER_SET;
1028		tag = ber_next_element( ber, &len, dn_end )) {
1029		nrdns++;
1030		for ( tag = ber_first_element( ber, &len, &rdn_end );
1031			tag == LBER_SEQUENCE;
1032			tag = ber_next_element( ber, &len, rdn_end )) {
1033			tag = ber_skip_tag( ber, &len );
1034			ber_skip_data( ber, len );
1035			navas++;
1036		}
1037	}
1038
1039	/* Allocate the DN/RDN/AVA stuff as a single block */
1040	dnsize = sizeof(LDAPRDN) * (nrdns+1);
1041	dnsize += sizeof(LDAPAVA *) * (navas+nrdns);
1042	dnsize += sizeof(LDAPAVA) * navas;
1043	if (dnsize > sizeof(ptrs)) {
1044		newDN = (LDAPDN)LDAP_MALLOC( dnsize );
1045		if ( newDN == NULL )
1046			return LDAP_NO_MEMORY;
1047	} else {
1048		newDN = (LDAPDN)(char *)ptrs;
1049	}
1050
1051	newDN[nrdns] = NULL;
1052	newRDN = (LDAPRDN)(newDN + nrdns+1);
1053	newAVA = (LDAPAVA *)(newRDN + navas + nrdns);
1054	baseAVA = newAVA;
1055
1056	/* Rewind and start extracting */
1057	ber_rewind( ber );
1058
1059	tag = ber_first_element( ber, &len, &dn_end );
1060	for ( i = nrdns - 1; i >= 0; i-- ) {
1061		newDN[i] = newRDN;
1062
1063		for ( tag = ber_first_element( ber, &len, &rdn_end );
1064			tag == LBER_SEQUENCE;
1065			tag = ber_next_element( ber, &len, rdn_end )) {
1066
1067			*newRDN++ = newAVA;
1068			tag = ber_skip_tag( ber, &len );
1069			tag = ber_get_stringbv( ber, &Oid, LBER_BV_NOTERM );
1070			if ( tag != LBER_TAG_OID ) {
1071				rc = LDAP_DECODING_ERROR;
1072				goto nomem;
1073			}
1074
1075			oid2.bv_val = oidptr;
1076			oid2.bv_len = oidrem;
1077			if ( ber_decode_oid( &Oid, &oid2 ) < 0 ) {
1078				rc = LDAP_DECODING_ERROR;
1079				goto nomem;
1080			}
1081			oidname = find_oid( &oid2 );
1082			if ( !oidname ) {
1083				newAVA->la_attr = oid2;
1084				oidptr += oid2.bv_len + 1;
1085				oidrem -= oid2.bv_len + 1;
1086
1087				/* Running out of OID buffer space? */
1088				if (oidrem < 128) {
1089					if ( oidsize == 0 ) {
1090						oidsize = sizeof(oids) * 2;
1091						oidrem = oidsize;
1092						oidbuf = LDAP_MALLOC( oidsize );
1093						if ( oidbuf == NULL ) goto nomem;
1094						oidptr = oidbuf;
1095					} else {
1096						char *old = oidbuf;
1097						oidbuf = LDAP_REALLOC( oidbuf, oidsize*2 );
1098						if ( oidbuf == NULL ) goto nomem;
1099						/* Buffer moved! Fix AVA pointers */
1100						if ( old != oidbuf ) {
1101							LDAPAVA *a;
1102							long dif = oidbuf - old;
1103
1104							for (a=baseAVA; a<=newAVA; a++){
1105								if (a->la_attr.bv_val >= old &&
1106									a->la_attr.bv_val <= (old + oidsize))
1107									a->la_attr.bv_val += dif;
1108							}
1109						}
1110						oidptr = oidbuf + oidsize - oidrem;
1111						oidrem += oidsize;
1112						oidsize *= 2;
1113					}
1114				}
1115			} else {
1116				if ( func ) {
1117					newAVA->la_attr = oidname->oid;
1118				} else {
1119					newAVA->la_attr = oidname->name;
1120				}
1121			}
1122			tag = ber_get_stringbv( ber, &Val, LBER_BV_NOTERM );
1123			switch(tag) {
1124			case LBER_TAG_UNIVERSAL:
1125				/* This uses 32-bit ISO 10646-1 */
1126				csize = 4; goto to_utf8;
1127			case LBER_TAG_BMP:
1128				/* This uses 16-bit ISO 10646-1 */
1129				csize = 2; goto to_utf8;
1130			case LBER_TAG_TELETEX:
1131				/* This uses 8-bit, assume ISO 8859-1 */
1132				csize = 1;
1133to_utf8:		rc = ldap_ucs_to_utf8s( &Val, csize, &newAVA->la_value );
1134				newAVA->la_flags |= LDAP_AVA_FREE_VALUE;
1135				if (rc != LDAP_SUCCESS) goto nomem;
1136				newAVA->la_flags = LDAP_AVA_NONPRINTABLE;
1137				break;
1138			case LBER_TAG_UTF8:
1139				newAVA->la_flags = LDAP_AVA_NONPRINTABLE;
1140				/* This is already in UTF-8 encoding */
1141			case LBER_TAG_IA5:
1142			case LBER_TAG_PRINTABLE:
1143				/* These are always 7-bit strings */
1144				newAVA->la_value = Val;
1145			default:
1146				;
1147			}
1148			newAVA->la_private = NULL;
1149			newAVA->la_flags = LDAP_AVA_STRING;
1150			newAVA++;
1151		}
1152		*newRDN++ = NULL;
1153		tag = ber_next_element( ber, &len, dn_end );
1154	}
1155
1156	if ( func ) {
1157		rc = func( newDN, flags, NULL );
1158		if ( rc != LDAP_SUCCESS )
1159			goto nomem;
1160	}
1161
1162	rc = ldap_dn2bv_x( newDN, bv, LDAP_DN_FORMAT_LDAPV3, NULL );
1163
1164nomem:
1165	for (;baseAVA < newAVA; baseAVA++) {
1166		if (baseAVA->la_flags & LDAP_AVA_FREE_ATTR)
1167			LDAP_FREE( baseAVA->la_attr.bv_val );
1168		if (baseAVA->la_flags & LDAP_AVA_FREE_VALUE)
1169			LDAP_FREE( baseAVA->la_value.bv_val );
1170	}
1171
1172	if ( oidsize != 0 )
1173		LDAP_FREE( oidbuf );
1174	if ( newDN != (LDAPDN)(char *) ptrs )
1175		LDAP_FREE( newDN );
1176	return rc;
1177}
1178
1179