使用SNI在一个盒子中提供多个域

 欢不是欢7 发布于 2023-01-18 13:04

我在FreeBSD-8.2中使用OpenSSL 0.9.8q.我的系统上有3个虚拟主机,并希望在一台服务器上实现SNI以服务所有3个虚拟主机.

我每个都有3个单独的证书,在我的ssl-server代码中,我必须以某种方式找出客户端请求的域名是什么,并使用相应的证书文件.为此,我编写了一个名为的函数,get_ssl_servername_cb并将其作为回调函数传递给SSL_CTX_set_tlsext_servername_callback.这样,在回调函数中,我可以得到客户端请求的域名.

但我的问题是,这个回调函数正在执行函数后执行SSL_accept,但我必须在使用SSL_new命令之前选择并使用相应的证书,这是执行之前的方式SSL_accept.

所以我的问题是,我如何使用SSL_CTX_set_tlsext_servername_callbackSNI函数?

1 个回答
  • 但我的问题是,这个回调函数在执行"SSL_accept"函数后正在执行,但我必须在使用"SSL_new"命令之前选择并使用相应的证书,这是执行SSL_accept之前的方法.

    启动服务器时,提供默认值SSL_CTX.这用于非SNI客户端,如SSLv3客户端和不使用SNI的TLS客户端(如Windows XP).这是必需的,因为在这种情况下不会调用回调.

    下面是一些使用OpenSSL来解释行为的示例s_client.要模拟非SNI客户端以便get_ssl_servername_cb 调用您,请发出:

    openssl s_client -connect localhost:8443 -ssl3 #SNI在TLSv1添加

    openssl s_client -connect localhost:8443 -tls1 #Windows XP客户端

    为了模拟SNI客户端,以便您get_ssl_servername_cb 调用,问题:

    openssl s_client -connect localhost:8443 -tls1 -servername localhost

    您还可以通过添加来避免证书验证错误-CAfile.这来自我的一个测试脚本(用于测试DSS/DSA证书localhost):

    printf "GET / HTTP/1.1\r\n\r\n" | /usr/local/ssl/bin/openssl s_client \
        -connect localhost:8443 -tls1 -servername localhost \
        -CAfile pki/signing-dss-cert.pem 
    

    所以我的问题是,如何为SNI使用"SSL_CTX_set_tlsext_servername_callback"功能?

    请参阅OpenSSL源代码<openssl dir>/apps/s_server.c; 或者参见如何在C或C++中的OpenSSL上实现服务器名称指示(SNI)?.

    get_ssl_servername_cb(设置为SSL_CTX_set_tlsext_servername_callback)中,检查服务器名称.出现以下两种情况之一:您已经拥有SSL_CTX服务器名称,或者您需要创建SSL_CTX服务器名称.

    SSL_CTX从缓存中获取或创建新缓存后SSL_CTX,您可以使用SSL_set_SSL_CTX交换上下文.有一个在OpenSSL源文件中交换新上下文的示例.请参阅s_server.c(in <openssl dir>/apps/s_server.c)的代码.跟着小道ctx2,

    这是我的一个项目中的样子.IsDomainInDefaultCert确定默认服务器证书是否提供了所请求的服务器名称.如果没有,请GetServerContext提取所需内容SSL_CTX.GetServerContext从应用级缓存中提取所需的证书; 或创建它并将其放入应用程序级缓存(GetServerContext也断言一个引用计数,SSL_CTX以便OpenSSL库不会从应用程序下删除它).

    static int ServerNameCallback(SSL *ssl, int *ad, void *arg)
    {
        UNUSED(ad);
        UNUSED(arg);
    
        ASSERT(ssl);
        if (ssl == NULL)
            return SSL_TLSEXT_ERR_NOACK;
    
        const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
        ASSERT(servername && servername[0]);
        if (!servername || servername[0] == '\0')
            return SSL_TLSEXT_ERR_NOACK;
    
        /* Does the default cert already handle this domain? */
        if (IsDomainInDefCert(servername))
            return SSL_TLSEXT_ERR_OK;
    
        /* Need a new certificate for this domain */
        SSL_CTX* ctx = GetServerContext(servername);
        ASSERT(ctx != NULL);
        if (ctx == NULL)
            return SSL_TLSEXT_ERR_NOACK;   
    
        /* Useless return value */
        SSL_CTX* v = SSL_set_SSL_CTX(ssl, ctx);
        ASSERT(v == ctx);
        if (v != ctx)   
            return SSL_TLSEXT_ERR_NOACK;
    
        return SSL_TLSEXT_ERR_OK;
    }
    

    在上面的代码,ad并且arg是未使用的参数.我不知道是什么ad原因,因为我不使用它.arg可用于将上下文传递给回调.我也没有使用arg它,而是s_server.c使用它来打印一些调试信息(这arg是一个指向BIOs stderr(和其他一些)的指针,IIRC).


    为了完整性,SSL_CTX参考计数,它们可以重复使用.新创建SSL_CTX的计数为1,委托给OpenSSL内部缓存机制.当您SSL_CTXSSL对象移交给对象时,计数增加到2.当SSL对象调用SSL_CTX_freeSSL_CTX,该函数将减少引用计数.如果上下文已过期且引用计数为1,则OpenSSL库将从其内部缓存中删除它.

    2023-01-18 13:06 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有