でクライアントを検証することを選択できることはわかっていますが--ssl-verify
、使用するCAチェーンを指定するにはどうすればよいですか?私は(curl--cacert
やWEBrickのよう:SSLCACertificateFile
に)ファイルを提供することに慣れているので、ファイルを用意しましたが、ファイルをに渡す方法に関するドキュメントが見つからないようですthin
。
1 に答える
簡単な答え:できません。
長い答え:可能ですが、SSL接続を構築するEventMachineのC ++拡張機能を更新し、認証局ファイルを渡すためにEventMachineとThinを介して呼び出しスタックを更新する必要があります。
私がこれを見つけた方法:ソースコード!すべてgithubにあります
thinのコマンドラインoptsはで解析されます
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 = case when cluster? then Controllers::Cluster.new(@options) when service? then Controllers::Service.new(@options) else Controllers::Controller.new(@options) end
sslでは
thin:lib/controllers/controller.rb
、オプションがプルバックされ、サーバーオブジェクトとともに保存されます。# 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
、5つの引数の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; }
バニラC関数
evma_set_tls_parms
はで定義されていeventmachine:ext/cmain.cpp
ます。sslオプションをEventableDescriptor
のSetTlsParms
メソッドに渡します。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
標準のOpenSSLCバインディングでこれらのオプションを使用する同じファイルで定義されます。// 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
、さらに2、3回の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);
これを行うためのパッチを提出することは、十分な意欲のある人のための演習として残されています。