X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Ftls2.c;h=1feba5befd56ceef025d91c15d2fc0c6313f1ec0;hb=8e34ed8c786a1f786976da046907f7dbd5d3458d;hp=9afda820d5c48e70c4cf3d7319b7180b86df6a5a;hpb=a8bb1769f5eb03f72ee101054c128d47d9fbb46a;p=openldap diff --git a/libraries/libldap/tls2.c b/libraries/libldap/tls2.c index 9afda820d5..1feba5befd 100644 --- a/libraries/libldap/tls2.c +++ b/libraries/libldap/tls2.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2014 The OpenLDAP Foundation. + * Copyright 1998-2017 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,7 +43,9 @@ static tls_impl *tls_imp = &ldap_int_tls_impl; #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 @@ -136,6 +138,14 @@ ldap_int_tls_destroy( struct ldapoptions *lo ) 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 ); } /* @@ -199,7 +209,9 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) 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; } @@ -327,7 +339,7 @@ update_flags( Sockbuf *sb, tls_session * ssl, int rc ) */ 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; @@ -372,6 +384,10 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) errno = WSAGetLastError(); #endif + if ( err == 0 ) { + err = ldap_pvt_tls_check_hostname( ld, ssl, host ); + } + if ( err < 0 ) { char buf[256], *msg; @@ -502,7 +518,27 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in ) { 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 @@ -518,6 +554,7 @@ ldap_pvt_tls_config( LDAP *ld, int option, const char *arg ) 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 ); @@ -732,6 +769,33 @@ ldap_pvt_tls_get_option( LDAP *ld, int 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; @@ -864,6 +928,107 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) 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; } @@ -904,7 +1069,7 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) * 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; @@ -919,7 +1084,7 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) #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 */ @@ -939,8 +1104,8 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) 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; @@ -987,7 +1152,7 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) } } 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 */ @@ -997,20 +1162,6 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) 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; }