diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb index bcb167e..5f688db 100644 --- a/ext/openssl/lib/openssl/ssl.rb +++ b/ext/openssl/lib/openssl/ssl.rb @@ -70,7 +70,7 @@ class SSLContext DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL end - INIT_VARS = ["cert", "key", "client_ca", "ca_file", "ca_path", + INIT_VARS = ["client_ca", "ca_file", "ca_path", "timeout", "verify_mode", "verify_depth", "renegotiation_cb", "verify_callback", "cert_store", "extra_chain_cert", "client_cert_cb", "session_id_context", "tmp_dh_callback", @@ -106,6 +106,8 @@ class SSLContext # # You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS def initialize(version = nil, fallback_scsv: false) + @certs = [] + @keys = [] INIT_VARS.each { |v| instance_variable_set v, nil } self.options = self.options | OpenSSL::SSL::OP_ALL return unless version @@ -131,6 +132,22 @@ def set_params(params={}) end return params end + + # Compatibility with previous version supporting a single certificate + def cert=(cert) + self.certs = [cert] + end + def cert + + self.certs.first + end + + def key=(key) + self.keys = [key] + end + def key + self.keys.first + end end module SocketForwarder diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 9f7ee0b..9437793 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -36,8 +36,8 @@ VALUE cSSLSocket; static VALUE eSSLErrorWaitReadable; static VALUE eSSLErrorWaitWritable; -#define ossl_sslctx_set_cert(o,v) rb_iv_set((o),"@cert",(v)) -#define ossl_sslctx_set_key(o,v) rb_iv_set((o),"@key",(v)) +#define ossl_sslctx_set_certs(o,v) rb_iv_set((o),"@certs",(v)) +#define ossl_sslctx_set_keys(o,v) rb_iv_set((o),"@keys",(v)) #define ossl_sslctx_set_client_ca(o,v) rb_iv_set((o),"@client_ca",(v)) #define ossl_sslctx_set_ca_file(o,v) rb_iv_set((o),"@ca_file",(v)) #define ossl_sslctx_set_ca_path(o,v) rb_iv_set((o),"@ca_path",(v)) @@ -50,8 +50,8 @@ static VALUE eSSLErrorWaitWritable; #define ossl_sslctx_set_client_cert_cb(o,v) rb_iv_set((o),"@client_cert_cb",(v)) #define ossl_sslctx_set_sess_id_ctx(o, v) rb_iv_set((o),"@session_id_context",(v)) -#define ossl_sslctx_get_cert(o) rb_iv_get((o),"@cert") -#define ossl_sslctx_get_key(o) rb_iv_get((o),"@key") +#define ossl_sslctx_get_certs(o) rb_iv_get((o),"@certs") +#define ossl_sslctx_get_keys(o) rb_iv_get((o),"@keys") #define ossl_sslctx_get_client_ca(o) rb_iv_get((o),"@client_ca") #define ossl_sslctx_get_ca_file(o) rb_iv_get((o),"@ca_file") #define ossl_sslctx_get_ca_path(o) rb_iv_get((o),"@ca_path") @@ -713,7 +713,8 @@ ossl_sslctx_setup(VALUE self) char *ca_path = NULL, *ca_file = NULL; int verify_mode; long i; - VALUE val; + VALUE val, val2; + int cert_defined = 0, key_defined = 0; if(OBJ_FROZEN(self)) return Qnil; GetSSLCTX(self, ctx); @@ -761,19 +762,39 @@ ossl_sslctx_setup(VALUE self) } /* private key may be bundled in certificate file. */ - val = ossl_sslctx_get_cert(self); - cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */ - val = ossl_sslctx_get_key(self); - key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */ - if (cert && key) { - if (!SSL_CTX_use_certificate(ctx, cert)) { - /* Adds a ref => Safe to FREE */ - ossl_raise(eSSLError, "SSL_CTX_use_certificate"); + val = ossl_sslctx_get_certs(self); + if (!NIL_P(val)) { + Check_Type(val, T_ARRAY); + for (i = 0; i < RARRAY_LEN(val); i++) { + val2 = rb_ary_entry(val, i); + cert = NIL_P(val2) ? NULL : GetX509CertPtr(val2); /* NO DUP NEEDED */ + if (cert) { + cert_defined = 1; + if (!SSL_CTX_use_certificate(ctx, cert)) { + /* Adds a ref => Safe to FREE */ + ossl_raise(eSSLError, "SSL_CTX_use_certificate"); + } + } } - if (!SSL_CTX_use_PrivateKey(ctx, key)) { - /* Adds a ref => Safe to FREE */ - ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey"); + } + + val = ossl_sslctx_get_keys(self); + if (!NIL_P(val)) { + Check_Type(val, T_ARRAY); + for (i = 0; i < RARRAY_LEN(val); i++) { + val2 = rb_ary_entry(val, i); + key = NIL_P(val2) ? NULL : GetPKeyPtr(val2); /* NO DUP NEEDED */ + if (cert) { + key_defined = 1; + if (!SSL_CTX_use_PrivateKey(ctx, key)) { + /* Adds a ref => Safe to FREE */ + ossl_raise(eSSLError, "SSL_CTX_use_certificate"); + } + } } + } + + if (cert_defined && key_defined) { if (!SSL_CTX_check_private_key(ctx)) { ossl_raise(eSSLError, "SSL_CTX_check_private_key"); } @@ -2128,14 +2149,14 @@ Init_ossl_ssl(void) rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc); /* - * Context certificate + * Context certificates */ - rb_attr(cSSLContext, rb_intern("cert"), 1, 1, Qfalse); + rb_attr(cSSLContext, rb_intern("certs"), 1, 1, Qfalse); /* - * Context private key + * Context private keys */ - rb_attr(cSSLContext, rb_intern("key"), 1, 1, Qfalse); + rb_attr(cSSLContext, rb_intern("keys"), 1, 1, Qfalse); /* * A certificate or Array of certificates that will be sent to the client.