/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2014 The OpenLDAP Foundation.
+ * Copyright 1998-2018 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#endif /* HAVE_TLS */
+#ifndef HAVE_MOZNSS
#define LDAP_USE_NON_BLOCKING_TLS
+#endif
/* RFC2459 minimum required set of supported attribute types
* in a certificate DN
LDAP_FREE( lo->ldo_tls_crlfile );
lo->ldo_tls_crlfile = NULL;
}
+ /* tls_pin_hashalg and tls_pin share the same buffer */
+ if ( lo->ldo_tls_pin_hashalg ) {
+ LDAP_FREE( lo->ldo_tls_pin_hashalg );
+ lo->ldo_tls_pin_hashalg = NULL;
+ } else {
+ LDAP_FREE( lo->ldo_tls_pin.bv_val );
+ }
+ BER_BVZERO( &lo->ldo_tls_pin );
}
/*
tls_init( ti );
if ( is_server && !lts.lt_certfile && !lts.lt_keyfile &&
- !lts.lt_cacertfile && !lts.lt_cacertdir ) {
+ !lts.lt_cacertfile && !lts.lt_cacertdir &&
+ !lts.lt_cacert.bv_val && !lts.lt_cert.bv_val &&
+ !lts.lt_key.bv_val ) {
/* minimum configuration not provided */
return LDAP_NOT_SUPPORTED;
}
*/
static int
-ldap_int_tls_connect( LDAP *ld, LDAPConn *conn )
+ldap_int_tls_connect( LDAP *ld, LDAPConn *conn, const char *host )
{
Sockbuf *sb = conn->lconn_sb;
int err;
errno = WSAGetLastError();
#endif
+ if ( err == 0 ) {
+ err = ldap_pvt_tls_check_hostname( ld, ssl, host );
+ }
+
if ( err < 0 )
{
char buf[256], *msg;
{
tls_session *session = s;
- return tls_imp->ti_session_chkhost( ld, session, name_in );
+ if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER &&
+ ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) {
+ ld->ld_errno = tls_imp->ti_session_chkhost( ld, session, name_in );
+ if (ld->ld_errno != LDAP_SUCCESS) {
+ return ld->ld_errno;
+ }
+ }
+
+ /*
+ * If instructed to do pinning, do it now
+ */
+ if ( !BER_BVISNULL( &ld->ld_options.ldo_tls_pin ) ) {
+ ld->ld_errno = tls_imp->ti_session_pinning( ld, s,
+ ld->ld_options.ldo_tls_pin_hashalg,
+ &ld->ld_options.ldo_tls_pin );
+ if (ld->ld_errno != LDAP_SUCCESS) {
+ return ld->ld_errno;
+ }
+ }
+
+ return LDAP_SUCCESS;
}
int
case LDAP_OPT_X_TLS_RANDOM_FILE:
case LDAP_OPT_X_TLS_CIPHER_SUITE:
case LDAP_OPT_X_TLS_DHFILE:
+ case LDAP_OPT_X_TLS_PEERKEY_HASH:
case LDAP_OPT_X_TLS_CRLFILE: /* GnuTLS only */
return ldap_pvt_tls_set_option( ld, option, (void *) arg );
}
break;
}
+ case LDAP_OPT_X_TLS_CACERT: {
+ struct berval *bv = arg;
+ if ( lo->ldo_tls_cacert.bv_val ) {
+ ber_dupbv( bv, &lo->ldo_tls_cacert );
+ } else {
+ BER_BVZERO( bv );
+ }
+ break;
+ }
+ case LDAP_OPT_X_TLS_CERT: {
+ struct berval *bv = arg;
+ if ( lo->ldo_tls_cert.bv_val ) {
+ ber_dupbv( bv, &lo->ldo_tls_cert );
+ } else {
+ BER_BVZERO( bv );
+ }
+ break;
+ }
+ case LDAP_OPT_X_TLS_KEY: {
+ struct berval *bv = arg;
+ if ( lo->ldo_tls_key.bv_val ) {
+ ber_dupbv( bv, &lo->ldo_tls_key );
+ } else {
+ BER_BVZERO( bv );
+ }
+ break;
+ }
default:
return -1;
ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
lo->ldo_tls_ctx = NULL;
return ldap_int_tls_init_ctx( lo, *(int *)arg );
+ case LDAP_OPT_X_TLS_CACERT:
+ if ( lo->ldo_tls_cacert.bv_val )
+ LDAP_FREE( lo->ldo_tls_cacert.bv_val );
+ if ( arg ) {
+ lo->ldo_tls_cacert.bv_len = ((struct berval *)arg)->bv_len;
+ lo->ldo_tls_cacert.bv_val = LDAP_MALLOC( lo->ldo_tls_cacert.bv_len );
+ if ( !lo->ldo_tls_cacert.bv_val )
+ return -1;
+ AC_MEMCPY( lo->ldo_tls_cacert.bv_val, ((struct berval *)arg)->bv_val, lo->ldo_tls_cacert.bv_len );
+ } else {
+ BER_BVZERO( &lo->ldo_tls_cacert );
+ }
+ break;
+ case LDAP_OPT_X_TLS_CERT:
+ if ( lo->ldo_tls_cert.bv_val )
+ LDAP_FREE( lo->ldo_tls_cert.bv_val );
+ if ( arg ) {
+ lo->ldo_tls_cert.bv_len = ((struct berval *)arg)->bv_len;
+ lo->ldo_tls_cert.bv_val = LDAP_MALLOC( lo->ldo_tls_cert.bv_len );
+ if ( !lo->ldo_tls_cert.bv_val )
+ return -1;
+ AC_MEMCPY( lo->ldo_tls_cert.bv_val, ((struct berval *)arg)->bv_val, lo->ldo_tls_cert.bv_len );
+ } else {
+ BER_BVZERO( &lo->ldo_tls_cert );
+ }
+ break;
+ case LDAP_OPT_X_TLS_KEY:
+ if ( lo->ldo_tls_key.bv_val )
+ LDAP_FREE( lo->ldo_tls_key.bv_val );
+ if ( arg ) {
+ lo->ldo_tls_key.bv_len = ((struct berval *)arg)->bv_len;
+ lo->ldo_tls_key.bv_val = LDAP_MALLOC( lo->ldo_tls_key.bv_len );
+ if ( !lo->ldo_tls_key.bv_val )
+ return -1;
+ AC_MEMCPY( lo->ldo_tls_key.bv_val, ((struct berval *)arg)->bv_val, lo->ldo_tls_key.bv_len );
+ } else {
+ BER_BVZERO( &lo->ldo_tls_key );
+ }
+ break;
+ case LDAP_OPT_X_TLS_PEERKEY_HASH: {
+ /* arg = "[hashalg:]pubkey_hash" */
+ struct berval bv;
+ char *p, *pin = arg;
+ int rc = LDAP_SUCCESS;
+
+ if ( !tls_imp->ti_session_pinning ) return -1;
+
+ if ( !pin ) {
+ if ( lo->ldo_tls_pin_hashalg ) {
+ LDAP_FREE( lo->ldo_tls_pin_hashalg );
+ } else if ( lo->ldo_tls_pin.bv_val ) {
+ LDAP_FREE( lo->ldo_tls_pin.bv_val );
+ }
+ lo->ldo_tls_pin_hashalg = NULL;
+ BER_BVZERO( &lo->ldo_tls_pin );
+ return rc;
+ }
+
+ pin = LDAP_STRDUP( pin );
+ p = strchr( pin, ':' );
+
+ /* pubkey (its hash) goes in bv, alg in p */
+ if ( p ) {
+ *p = '\0';
+ bv.bv_val = p+1;
+ p = pin;
+ } else {
+ bv.bv_val = pin;
+ }
+
+ bv.bv_len = strlen(bv.bv_val);
+ if ( ldap_int_decode_b64_inplace( &bv ) ) {
+ LDAP_FREE( pin );
+ return -1;
+ }
+
+ if ( ld != NULL ) {
+ LDAPConn *conn = ld->ld_defconn;
+ if ( conn != NULL ) {
+ Sockbuf *sb = conn->lconn_sb;
+ void *sess = ldap_pvt_tls_sb_ctx( sb );
+ if ( sess != NULL ) {
+ rc = tls_imp->ti_session_pinning( ld, sess, p, &bv );
+ }
+ }
+ }
+
+ if ( rc == LDAP_SUCCESS ) {
+ if ( lo->ldo_tls_pin_hashalg ) {
+ LDAP_FREE( lo->ldo_tls_pin_hashalg );
+ } else if ( lo->ldo_tls_pin.bv_val ) {
+ LDAP_FREE( lo->ldo_tls_pin.bv_val );
+ }
+ lo->ldo_tls_pin_hashalg = p;
+ lo->ldo_tls_pin = bv;
+ } else {
+ LDAP_FREE( pin );
+ }
+
+ return rc;
+ }
default:
return -1;
}
* Use non-blocking io during SSL Handshake when a timeout is configured
*/
if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
- ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, sb );
+ ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_NONBLOCK, (void*)1 );
ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
tv = ld->ld_options.ldo_tm_net;
tv0 = tv;
#endif /* LDAP_USE_NON_BLOCKING_TLS */
ld->ld_errno = LDAP_SUCCESS;
- ret = ldap_int_tls_connect( ld, conn );
+ ret = ldap_int_tls_connect( ld, conn, host );
#ifdef LDAP_USE_NON_BLOCKING_TLS
while ( ret > 0 ) { /* this should only happen for non-blocking io */
break;
} else {
/* ldap_int_poll called ldap_pvt_ndelay_off */
- ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, sb );
- ret = ldap_int_tls_connect( ld, conn );
+ ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_NONBLOCK, (void*)1 );
+ ret = ldap_int_tls_connect( ld, conn, host );
if ( ret > 0 ) { /* need to call tls_connect once more */
struct timeval curr_time_tv, delta_tv;
}
}
if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
- ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, NULL );
+ ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_NONBLOCK, NULL );
}
#endif /* LDAP_USE_NON_BLOCKING_TLS */
return (ld->ld_errno);
}
- ssl = ldap_pvt_tls_sb_ctx( sb );
- assert( ssl != NULL );
-
- /*
- * compare host with name(s) in certificate
- */
- if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER &&
- ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) {
- ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host );
- if (ld->ld_errno != LDAP_SUCCESS) {
- return ld->ld_errno;
- }
- }
-
return LDAP_SUCCESS;
}