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