gpt4 book ai didi

ruby - 使用 thin 时如何选择证书颁发机构文件?

转载 作者:太空宇宙 更新时间:2023-11-03 17:55:33 27 4
gpt4 key购买 nike

我知道我可以选择使用 --ssl-verify 来验证客户端,但是我如何指定我想使用哪个 CA 链?我习惯于提供一个文件(比如 curl 的 --cacert 或 WEBrick 的 :SSLCACertificateFile),所以我已经准备好了,但我似乎做不到查找有关如何将其传递给 thin 的文档。

最佳答案

简答:你不能。

长答案:你可以,但你必须更新 EventMachine 的构建 ssl 连接的 C++ 扩展,并通过 EventMachine 和 Thin 更新调用堆栈以传递证书颁发机构文件。

我是怎么发现的:源代码!都在github上

  • thin 的命令行选项在 thin:lib/thin/runner.rb 中解析

    opts.separator "SSL options:"

    opts.on( "--ssl", "Enables SSL") { @options[:ssl] = true }
    opts.on( "--ssl-key-file PATH", "Path to private key") { |path| @options[:ssl_key_file] = path }
    opts.on( "--ssl-cert-file PATH", "Path to certificate") { |path| @options[:ssl_cert_file] = path }
    opts.on( "--ssl-verify", "Enables SSL certificate verification") { @options[:ssl_verify] = true }
  • 然后用来创建 Controller

    controller = case
    when cluster? then Controllers::Cluster.new(@options)
    when service? then Controllers::Service.new(@options)
    else Controllers::Controller.new(@options)
    end
  • thin:lib/controllers/controller.rb ssl 选项被拉回以与服务器对象一起存储

    # ssl support
    if @options[:ssl]
    server.ssl = true
    server.ssl_options = { :private_key_file => @options[:ssl_key_file], :cert_chain_file => @options[:ssl_cert_file], :verify_peer => @options[:ssl_verify] }
    end
  • 最后用于初始化与客户端的连接

    def initialize_connection(connection)
    connection.backend = self
    connection.app = @server.app
    connection.comm_inactivity_timeout = @timeout
    connection.threaded = @threaded

    if @ssl
    connection.start_tls(@ssl_options)
    end
  • 此连接是一个 EventMachine::Connection , 在 eventmachine:lib/em/connection.rb 中定义. EventMachine::Connection#start_tls将参数传递给 EventMachine::set_tls_parms .

    def start_tls args={}
    priv_key, cert_chain, verify_peer = args.values_at(:private_key_file, :cert_chain_file, :verify_peer)

    [priv_key, cert_chain].each do |file|
    next if file.nil? or file.empty?
    raise FileNotFoundException,
    "Could not find #{file} for start_tls" unless File.exists? file
    end

    EventMachine::set_tls_parms(@signature, priv_key || '', cert_chain || '', verify_peer)
    EventMachine::start_tls @signature
    end
  • EventMachine::set_tls_parms是 C++ 扩展的一部分,在 eventmachine:ext/rubymain.cpp 中定义作为五参数 C 函数 t_set_tls_parms

    rb_define_module_function (EmModule, "set_tls_parms", (VALUE(*)(...))t_set_tls_parms, 4);
  • t_set_tls_parms在同一文件的其他地方定义只是将 ssl 选项传递给 evma_set_tls_parms .

    static VALUE t_set_tls_parms (VALUE self, VALUE signature, VALUE privkeyfile, VALUE certchainfile, VALUE verify_peer)
    {
    /* set_tls_parms takes a series of positional arguments for specifying such things
    * as private keys and certificate chains.
    * It's expected that the parameter list will grow as we add more supported features.
    * ALL of these parameters are optional, and can be specified as empty or NULL strings.
    */
    evma_set_tls_parms (NUM2ULONG (signature), StringValuePtr (privkeyfile), StringValuePtr (certchainfile), (verify_peer == Qtrue ? 1 : 0));
    return Qnil;
    }
  • Vanilla C 函数 evma_set_tls_parmseventmachine:ext/cmain.cpp 中定义.它将 ssl 选项传递给 EventableDescriptorSetTlsParms方法:

    extern "C" void evma_set_tls_parms (const unsigned long binding, const char *privatekey_filename, const char *certchain_filename, int verify_peer)
    {
    ensure_eventmachine("evma_set_tls_parms");
    EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
    if (ed)
    ed->SetTlsParms (privatekey_filename, certchain_filename, (verify_peer == 1 ? true : false));
    }
  • 那个SetTlsParms实例方法在 eventmachine:ed.cpp 中定义,它真正做的就是在一些实例变量中缓存 ssl 选项。

    void ConnectionDescriptor::SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer)
    {
    #ifdef WITH_SSL
    if (SslBox)
    throw std::runtime_error ("call SetTlsParms before calling StartTls");
    if (privkey_filename && *privkey_filename)
    PrivateKeyFilename = privkey_filename;
    if (certchain_filename && *certchain_filename)
    CertChainFilename = certchain_filename;
    bSslVerifyPeer = verify_peer;
    #endif

    #ifdef WITHOUT_SSL
    throw std::runtime_error ("Encryption not available on this event-machine");
    #endif
    }
  • 这些实例变量稍后会在 StartTls 中使用实例方法(在同一个文件中定义),并传递给初始化一个新的 SslBox_t

    void ConnectionDescriptor::StartTls()
    {
    #ifdef WITH_SSL
    if (SslBox)
    throw std::runtime_error ("SSL/TLS already running on connection");

    SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename, bSslVerifyPeer, GetBinding());
    _DispatchCiphertext();
    #endif
  • SslBox_t构造函数在 eventmachine:ext/ssl.cpp 中定义,它使用 ssl 选项初始化一个新的 SslContext_t .

    SslBox_t::SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile, bool verify_peer, const unsigned long binding):
    bIsServer (is_server),
    bHandshakeCompleted (false),
    bVerifyPeer (verify_peer),
    pSSL (NULL),
    pbioRead (NULL),
    pbioWrite (NULL)
    {
    /* TODO someday: make it possible to re-use SSL contexts so we don't have to create
    * a new one every time we come here.
    */

    Context = new SslContext_t (bIsServer, privkeyfile, certchainfile);
    assert (Context);
  • SslContext_t构造函数在同一文件中定义,在该文件中它将这些选项与标准 OpenSSL C 绑定(bind)一起使用:

    // The SSL_CTX calls here do NOT allocate memory.
    int e;
    if (privkeyfile.length() > 0)
    e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM);
    else
    e = SSL_CTX_use_PrivateKey (pCtx, DefaultPrivateKey);
    if (e <= 0) ERR_print_errors_fp(stderr);
    assert (e > 0);

    if (certchainfile.length() > 0)
    e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str());
    else
    e = SSL_CTX_use_certificate (pCtx, DefaultCertificate);
    if (e <= 0) ERR_print_errors_fp(stderr);
    assert (e > 0);

现在我们知道如何使用 ssl 选项了。如果调用链被修改为将 CA 文件名与其余部分一起传递到这一点,例如 const string &certauthfile ,我们可以使用更多的 OpenSSL 调用来添加权限文件:

if (certauthfile.length() > 0)
e = SSL_CTX_load_verify_locations(pCtx, certauthfile.c_str(), NULL);
else
;// no default necessary
if (e <= 0) ERR_print_errors_fp(stderr);
assert (e > 0);

提交补丁来做到这一点留给有足够动力的人练习。

关于ruby - 使用 thin 时如何选择证书颁发机构文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14470042/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com