Class: OpenSSL::SSL::SSLContext

Inherits:
Object
  • Object
show all
Defined in:
ossl_ssl.c,
lib/openssl/ssl.rb,
ossl_ssl.c

Overview

An SSLContext is used to set various options regarding certificates, algorithms, verification, session caching, etc. The SSLContext is used to create an SSLSocket.

All attributes must be set before creating an SSLSocket as the SSLContext will be frozen afterward.

The following attributes are available but don't show up in rdoc:

  • ssl_version, cert, key, client_ca, ca_file, ca_path, timeout,

  • verify_mode, verify_depth client_cert_cb, tmp_dh_callback,

  • session_id_context, session_add_cb, session_new_cb, session_remove_cb

Constant Summary collapse

DEFAULT_PARAMS =
{
  :ssl_version => "SSLv23",
  :verify_mode => OpenSSL::SSL::VERIFY_PEER,
  :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW",
  :options => defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS) ?
    OpenSSL::SSL::OP_ALL & ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS :
    OpenSSL::SSL::OP_ALL,
}
DEFAULT_CERT_STORE =
OpenSSL::X509::Store.new
SESSION_CACHE_OFF =

No session caching for client or server

LONG2FIX(SSL_SESS_CACHE_OFF)
SESSION_CACHE_CLIENT =

doesn't actually do anything in 0.9.8e

LONG2FIX(SSL_SESS_CACHE_CLIENT)
SESSION_CACHE_SERVER =

Server sessions are added to the session cache

LONG2FIX(SSL_SESS_CACHE_SERVER)
SESSION_CACHE_BOTH =

no different than CACHE_SERVER in 0.9.8e

LONG2FIX(SSL_SESS_CACHE_BOTH)
SESSION_CACHE_NO_AUTO_CLEAR =

Normally the session cache is checked for expired sessions every 255 connections. Since this may lead to a delay that cannot be controlled, the automatic flushing may be disabled and #flush_sessions can be called explicitly.

LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR)
SESSION_CACHE_NO_INTERNAL_LOOKUP =

Always perform external lookups of sessions even if they are in the internal cache.

This flag has no effect on clients

LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)
SESSION_CACHE_NO_INTERNAL_STORE =

Never automatically store sessions in the internal store.

LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE)
SESSION_CACHE_NO_INTERNAL =

Enables both SESSION_CACHE_NO_INTERNAL_LOOKUP and SESSION_CACHE_NO_INTERNAL_STORE.

LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL)
METHODS =

The list of available SSL/TLS methods

ary

Instance Method Summary collapse

Constructor Details

#newObject #new(:TLSv1) ⇒ Object #new("SSLv23_client") ⇒ Object

You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'ossl_ssl.c', line 222

static VALUE
ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self)
{
    VALUE ssl_method;
    int i;

    for(i = 0; i < numberof(ossl_sslctx_attrs); i++){
	char buf[32];
	snprintf(buf, sizeof(buf), "@%s", ossl_sslctx_attrs[i]);
	rb_iv_set(self, buf, Qnil);
    }
    if (rb_scan_args(argc, argv, "01", &ssl_method) == 0){
        return self;
    }
    ossl_sslctx_set_ssl_version(self, ssl_method);

    return self;
}

Instance Method Details

#ciphersArray

The list of ciphers configured for this context.

Returns:

  • (Array)


835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
# File 'ossl_ssl.c', line 835

static VALUE
ossl_sslctx_get_ciphers(VALUE self)
{
    SSL_CTX *ctx;
    STACK_OF(SSL_CIPHER) *ciphers;
    SSL_CIPHER *cipher;
    VALUE ary;
    int i, num;

    Data_Get_Struct(self, SSL_CTX, ctx);
    if(!ctx){
        rb_warning("SSL_CTX is not initialized.");
        return Qnil;
    }
    ciphers = ctx->cipher_list;

    if (!ciphers)
        return rb_ary_new();

    num = sk_SSL_CIPHER_num(ciphers);
    ary = rb_ary_new2(num);
    for(i = 0; i < num; i++){
        cipher = sk_SSL_CIPHER_value(ciphers, i);
        rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher));
    }
    return ary;
}

#ciphers=Object

ctx.ciphers = [name, …]

ctx.ciphers = [[name, version, bits, alg_bits], ...]

Sets the list of available ciphers for this context. Note in a server context some ciphers require the appropriate certificates. For example, an RSA cipher can only be chosen when an RSA certificate is available.

See also OpenSSL::Cipher and OpenSSL::Cipher::ciphers



875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
# File 'ossl_ssl.c', line 875

static VALUE
ossl_sslctx_set_ciphers(VALUE self, VALUE v)
{
    SSL_CTX *ctx;
    VALUE str, elem;
    int i;

    rb_check_frozen(self);
    if (NIL_P(v))
	return v;
    else if (TYPE(v) == T_ARRAY) {
        str = rb_str_new(0, 0);
        for (i = 0; i < RARRAY_LEN(v); i++) {
            elem = rb_ary_entry(v, i);
            if (TYPE(elem) == T_ARRAY) elem = rb_ary_entry(elem, 0);
            elem = rb_String(elem);
            rb_str_append(str, elem);
            if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":");
        }
    } else {
        str = v;
        StringValue(str);
    }

    Data_Get_Struct(self, SSL_CTX, ctx);
    if(!ctx){
        ossl_raise(eSSLError, "SSL_CTX is not initialized.");
        return Qnil;
    }
    if (!SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(str))) {
        ossl_raise(eSSLError, "SSL_CTX_set_cipher_list");
    }

    return v;
}

#flush_sessions(time|nil) ⇒ self

Removes sessions in the internal cache that have expired at time.

Returns:

  • (self)


1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
# File 'ossl_ssl.c', line 1073

static VALUE
ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self)
{
    VALUE arg1;
    SSL_CTX *ctx;
    time_t tm = 0;

    rb_scan_args(argc, argv, "01", &arg1);

    Data_Get_Struct(self, SSL_CTX, ctx);

    if (NIL_P(arg1)) {
        tm = time(0);
    } else if (rb_obj_is_instance_of(arg1, rb_cTime)) {
        tm = NUM2LONG(rb_funcall(arg1, rb_intern("to_i"), 0));
    } else {
        ossl_raise(rb_eArgError, "arg must be Time or nil");
    }

    SSL_CTX_flush_sessions(ctx, (long)tm);

    return self;
}

#session_add(session) ⇒ Object

Adds session to the session cache



917
918
919
920
921
922
923
924
925
926
927
# File 'ossl_ssl.c', line 917

static VALUE
ossl_sslctx_session_add(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;
    SSL_SESSION *sess;

    Data_Get_Struct(self, SSL_CTX, ctx);
    SafeGetSSLSession(arg, sess);

    return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse;
}

#session_cache_modeInteger

The current session cache mode.

Returns:



953
954
955
956
957
958
959
960
961
# File 'ossl_ssl.c', line 953

static VALUE
ossl_sslctx_get_session_cache_mode(VALUE self)
{
    SSL_CTX *ctx;

    Data_Get_Struct(self, SSL_CTX, ctx);

    return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx));
}

#session_cache_mode=(integer) ⇒ Integer

Sets the SSL session cache mode. Bitwise-or together the desired SESSION_CACHE_* constants to set. See SSL_CTX_set_session_cache_mode(3) for details.

Returns:



971
972
973
974
975
976
977
978
979
980
981
# File 'ossl_ssl.c', line 971

static VALUE
ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;

    Data_Get_Struct(self, SSL_CTX, ctx);

    SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg));

    return arg;
}

#session_cache_sizeInteger

Returns the current session cache size. Zero is used to represent an unlimited cache size.

Returns:



990
991
992
993
994
995
996
997
998
# File 'ossl_ssl.c', line 990

static VALUE
ossl_sslctx_get_session_cache_size(VALUE self)
{
    SSL_CTX *ctx;

    Data_Get_Struct(self, SSL_CTX, ctx);

    return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx));
}

#session_cache_size=(integer) ⇒ Integer

Sets the session cache size. Returns the previously valid session cache size. Zero is used to represent an unlimited session cache size.

Returns:



1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
# File 'ossl_ssl.c', line 1007

static VALUE
ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;

    Data_Get_Struct(self, SSL_CTX, ctx);

    SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg));

    return arg;
}

#session_cache_statsHash

Returns a Hash containing the following keys:

:accept

Number of started SSL/TLS handshakes in server mode

:accept_good

Number of established SSL/TLS sessions in server mode

:accept_renegotiate

Number of start renegotiations in server mode

:cache_full

Number of sessions that were removed due to cache overflow

:cache_hits

Number of successfully reused connections

:cache_misses

Number of sessions proposed by clients that were not found

in the cache
:cache_num

Number of sessions in the internal session cache

:cb_hits

Number of sessions retrieved from the external cache in server

mode
:connect

Number of started SSL/TLS handshakes in client mode

:connect_good

Number of established SSL/TLS sessions in client mode

:connect_renegotiate

Number of start renegotiations in client mode

:timeouts

Number of sessions proposed by clients that were found in the

cache but had expired due to timeouts

Returns:

  • (Hash)


1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
# File 'ossl_ssl.c', line 1041

static VALUE
ossl_sslctx_get_session_cache_stats(VALUE self)
{
    SSL_CTX *ctx;
    VALUE hash;

    Data_Get_Struct(self, SSL_CTX, ctx);

    hash = rb_hash_new();
    rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));

    return hash;
}

#session_remove(session) ⇒ Object

Removes session from the session cache



935
936
937
938
939
940
941
942
943
944
945
# File 'ossl_ssl.c', line 935

static VALUE
ossl_sslctx_session_remove(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;
    SSL_SESSION *sess;

    Data_Get_Struct(self, SSL_CTX, ctx);
    SafeGetSSLSession(arg, sess);

    return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse;
}

#set_params(params = {}) ⇒ Object

Sets the parameters for this SSL context to the values in params. The keys in params must be assignment methods on SSLContext.

If the verify_mode is not VERIFY_NONE and ca_file, ca_path and cert_store are not set then the system default certificate store is used.



46
47
48
49
50
51
52
53
54
55
# File 'lib/openssl/ssl.rb', line 46

def set_params(params={})
  params = DEFAULT_PARAMS.merge(params)
  params.each{|name, value| self.__send__("#{name}=", value) }
  if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
    unless self.ca_file or self.ca_path or self.cert_store
      self.cert_store = DEFAULT_CERT_STORE
    end
  end
  return params
end

#setupQtrue #firstt time #setupObject

This method is called automatically when a new SSLSocket is created. Normally you do not need to call this method (unless you are writing an extension in C).

Overloads:

  • #setupQtrue #firstt time

    Returns:

    • (Qtrue #firstt time)


656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
# File 'ossl_ssl.c', line 656

static VALUE
ossl_sslctx_setup(VALUE self)
{
    SSL_CTX *ctx;
    X509 *cert = NULL, *client_ca = NULL;
    X509_STORE *store;
    EVP_PKEY *key = NULL;
    char *ca_path = NULL, *ca_file = NULL;
    int i, verify_mode;
    VALUE val;

    if(OBJ_FROZEN(self)) return Qnil;
    Data_Get_Struct(self, SSL_CTX, ctx);

#if !defined(OPENSSL_NO_DH)
    if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){
	SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
    }
    else{
	SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback);
    }
#endif
    SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self);

    val = ossl_sslctx_get_cert_store(self);
    if(!NIL_P(val)){
	/*
         * WORKAROUND:
	 *   X509_STORE can count references, but
	 *   X509_STORE_free() doesn't care it.
	 *   So we won't increment it but mark it by ex_data.
	 */
        store = GetX509StorePtr(val); /* NO NEED TO DUP */
        SSL_CTX_set_cert_store(ctx, store);
        SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1);
    }

    val = ossl_sslctx_get_extra_cert(self);
    if(!NIL_P(val)){
	rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, 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");
        }
        if (!SSL_CTX_use_PrivateKey(ctx, key)) {
            /* Adds a ref => Safe to FREE */
            ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
        }
        if (!SSL_CTX_check_private_key(ctx)) {
            ossl_raise(eSSLError, "SSL_CTX_check_private_key");
        }
    }

    val = ossl_sslctx_get_client_ca(self);
    if(!NIL_P(val)){
	if(TYPE(val) == T_ARRAY){
	    for(i = 0; i < RARRAY_LEN(val); i++){
		client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]);
        	if (!SSL_CTX_add_client_CA(ctx, client_ca)){
		    /* Copies X509_NAME => FREE it. */
        	    ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
        	}
	    }
        }
	else{
	    client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
            if (!SSL_CTX_add_client_CA(ctx, client_ca)){
		/* Copies X509_NAME => FREE it. */
        	ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
            }
	}
    }

    val = ossl_sslctx_get_ca_file(self);
    ca_file = NIL_P(val) ? NULL : StringValuePtr(val);
    val = ossl_sslctx_get_ca_path(self);
    ca_path = NIL_P(val) ? NULL : StringValuePtr(val);
    if(ca_file || ca_path){
	if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
	    rb_warning("can't set verify locations");
    }

    val = ossl_sslctx_get_verify_mode(self);
    verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
    SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
    if (RTEST(ossl_sslctx_get_client_cert_cb(self)))
	SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);

    val = ossl_sslctx_get_timeout(self);
    if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));

    val = ossl_sslctx_get_verify_dep(self);
    if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2INT(val));

    val = ossl_sslctx_get_options(self);
    if(!NIL_P(val)) {
    	SSL_CTX_set_options(ctx, NUM2LONG(val));
    } else {
	SSL_CTX_set_options(ctx, SSL_OP_ALL);
    }

#ifdef HAVE_OPENSSL_NPN_NEGOTIATED
    val = rb_iv_get(self, "@npn_protocols");
    if (!NIL_P(val)) {
	ssl_npn_encode_protocols(self, val);
	SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *) self);
	OSSL_Debug("SSL NPN advertise callback added");
    }
    if (RTEST(rb_iv_get(self, "@npn_select_cb"))) {
	SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
	OSSL_Debug("SSL NPN select callback added");
    }
#endif

    rb_obj_freeze(self);

    val = ossl_sslctx_get_sess_id_ctx(self);
    if (!NIL_P(val)){
	StringValue(val);
	if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
					    RSTRING_LENINT(val))){
	    ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
	}
    }

    if (RTEST(rb_iv_get(self, "@session_get_cb"))) {
	SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
	OSSL_Debug("SSL SESSION get callback added");
    }
    if (RTEST(rb_iv_get(self, "@session_new_cb"))) {
	SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
	OSSL_Debug("SSL SESSION new callback added");
    }
    if (RTEST(rb_iv_get(self, "@session_remove_cb"))) {
	SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
	OSSL_Debug("SSL SESSION remove callback added");
    }

#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
    val = rb_iv_get(self, "@servername_cb");
    if (!NIL_P(val)) {
        SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
	OSSL_Debug("SSL TLSEXT servername callback added");
    }
#endif

    return Qtrue;
}

#ssl_version=Object

ctx.ssl_version = “SSLv23_client”

You can get a list of valid versions with OpenSSL::SSL::SSLContext::METHODS



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'ossl_ssl.c', line 185

static VALUE
ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
{
    SSL_METHOD *method = NULL;
    const char *s;
    int i;

    SSL_CTX *ctx;
    if(TYPE(ssl_method) == T_SYMBOL)
	s = rb_id2name(SYM2ID(ssl_method));
    else
	s =  StringValuePtr(ssl_method);
    for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
        if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) {
            method = ossl_ssl_method_tab[i].func();
            break;
        }
    }
    if (!method) {
        ossl_raise(rb_eArgError, "unknown SSL method `%s'.", s);
    }
    Data_Get_Struct(self, SSL_CTX, ctx);
    if (SSL_CTX_set_ssl_version(ctx, method) != 1) {
        ossl_raise(eSSLError, "SSL_CTX_set_ssl_version");
    }

    return ssl_method;
}