OpenLDAP - 启用LDAP TLS连接的CRL检查

时间:2017-06-07 09:43:44

标签: ssl openssl ldap openldap tls1.2

我有一个使用TLS连接到LDAP服务器的客户端。对于此连接,我想启用CRL检查并仅在撤消任何服务器/客户端证书时拒绝连接。 在特殊情况下(如CRL丢失,CRL过期)我想忽略错误并建立连接。 所以我想覆盖默认的SSL验证回调以忽略特定的错误。

但是根本没有调用回叫。始终只调用默认回叫。

这是我的回电:

static int verify_callback(int ok, X509_STORE_CTX *ctx)
{
    X509* cert = X509_STORE_CTX_get_current_cert(ctx);
    if (ok)
        return ok;

    int sslRet = X509_STORE_CTX_get_error(ctx);
    const char* err = NULL;
    switch (sslRet)
    {
        case X509_V_ERR_UNABLE_TO_GET_CRL:
        case X509_V_ERR_CRL_HAS_EXPIRED:
        case X509_V_ERR_CRL_NOT_YET_VALID:
             printf( "CRL: Verification failed... but ignored : %d\n", sslRet);
              return 1;
        default:
            err = X509_verify_cert_error_string(sslRet);
            if (err)
                printf( "CRL: Failed to verify : %s\n",err);
            return 0;
    }
    return sslRet;
}

使用ldap回叫设置选项覆盖默认验证回叫:

void ldap_tls_cb(LDAP * ld, SSL * ssl, SSL_CTX * ctx, void * arg)
{
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER , verify_callback);
    printf("verify call back is set...\n");
    return;
}

主程序:

int main( int argc, char **argv )
{

    LDAP *ldap;
    int  auth_method    = LDAP_AUTH_SIMPLE; //LDAP_AUTH_SASL
    int  ldap_version   = LDAP_VERSION3;
    char *ldap_host     = "10.104.40.35";
    int   ldap_port     = 389;

    if ( (ldap = ldap_init(ldap_host, ldap_port)) == NULL ) {
        perror( "ldap_init failed" );
        return( EXIT_FAILURE );
    }

    int result = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
    if (result != LDAP_OPT_SUCCESS ) {
        ldap_perror(ldap, "ldap_set_option failed!");
        return(EXIT_FAILURE);
    }

    int requireCert = LDAP_OPT_X_TLS_DEMAND;
    result = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &requireCert);
    if (result != LDAP_OPT_SUCCESS ) {
        ldap_perror(ldap, "ldap_set_option - req cert -failed!");
        return(EXIT_FAILURE);
    }

    result = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, "/etc/certs/Cert.pem");
    if (result != LDAP_OPT_SUCCESS ) {
        ldap_perror(ldap, "ldap_set_option - cert file - failed!");
        return(EXIT_FAILURE);
    }

    int crlvalue = LDAP_OPT_X_TLS_CRL_ALL;
    result =ldap_set_option(NULL, LDAP_OPT_X_TLS_CRLCHECK, &crlvalue);
    if (result != LDAP_OPT_SUCCESS ) {
        ldap_perror(ldap, "ldap_set_option failed!");
        return(EXIT_FAILURE);
    }

    int debug = 7;
    ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &debug);

    result = ldap_set_option(ldap, LDAP_OPT_X_TLS_CONNECT_CB, (void *)ldap_tls_cb);
    if (result != LDAP_SUCCESS) {
        fprintf(stderr, "ldap_set_option(LDAP_OPT_X_TLS_CONNECT_CB): %s\n", ldap_err2string(result));
        return(1);
    }

    int msgidp = 0;
    result = ldap_start_tls(ldap,NULL,NULL,&msgidp);
    if (result != LDAP_OPT_SUCCESS ) {
        ldap_perror(ldap, "start tls failed!");
        return result;
    } else {
        printf("Start tls success.\n");
    }

    LDAPMessage     *resultm;
    struct timeval  timeout;
    result = ldap_result(ldap, msgidp, 0, &timeout, &resultm );
    if ( result == -1 || result == 0 ) {
        printf("ldap_result failed;retC=%d \n", result);
        return result;
    }

    result = ldap_parse_extended_result(ldap, resultm, NULL, NULL, 0 );
    if ( result == LDAP_SUCCESS ) {
        result = ldap_install_tls (ldap);
        printf("installing tls... %s\n", ldap_err2string(result));
    }

    int request_id = 0;
    result = ldap_sasl_bind(ldap, "", LDAP_SASL_SIMPLE, NULL, 0, 0, &request_id);

    if ( result != LDAP_SUCCESS ) {
        fprintf(stderr, "ldap_x_bind_s: %s\n", ldap_err2string(result));
        printf("LDAP bind error .. %d\n", result);
        return(EXIT_FAILURE);
    } else {
        printf("LDAP connection successful.\n");
    }

    ldap_unbind(ldap);
    return(EXIT_SUCCESS);
}

有人可以帮助检查我的验证回叫未被调用的原因吗?

1 个答案:

答案 0 :(得分:0)

我认为你需要直接在 SSL 对象上设置回调而不是上下文,所以

void ldap_tls_cb(LDAP * ld, SSL * ssl, SSL_CTX * ctx, void * arg)
{
    SSL_set_verify(ssl, SSL_VERIFY_PEER, verify_callback);
    printf("verify call back is set...\n");
    return;
}

这样做的原因是在调用连接回调时 SSL 句柄已经初始化(参见 the OpenLDAP code),并且 那个时候是too late to set this callback through the context

<块引用>

如果之前未设置特殊回调,则使用底层 ctx 的默认回调,该回调在使用 SSL_new(3) 创建 ssl 时有效。

OpenLDAP 可以使用 GnuTLS 构建,因此您可能需要在设置回调之前检查它是否使用 OpenSSL。 LDAP_OPT_X_TLS_PACKAGE 选项可用于此(请注意,我尚未测试此代码):

char* package = NULL;
int result = ldap_get_option(NULL, LDAP_OPT_X_TLS_PACKAGE, (void *)&package);
if (result != LDAP_OPT_SUCCESS) {
    ldap_perror(ldap, "ldap_get_option failed!");
    return(EXIT_FAILURE);
} else {
    if (strcmp(package, "OpenSSL") == 0) {
        // Set your callback
    }
    ldap_memfree(package);
}