Browse Source

Test for ECC curves support

master
aeris 2 years ago
parent
commit
04ae17945d
4 changed files with 469 additions and 16 deletions
  1. 1
    0
      Makefile
  2. 34
    9
      lib/cryptcheck/tls/server.rb
  3. 427
    0
      set_ecdh_curves.patch
  4. 7
    7
      tmp_key.patch

+ 1
- 0
Makefile View File

@@ -68,6 +68,7 @@ $(RUBY_DIR)/: build/$(RUBY_NAME).tar.gz
68 68
 
69 69
 $(RUBY_OPENSSL_EXT_DIR)/Makefile: libs | $(RUBY_DIR)/
70 70
 	patch -d $(RUBY_DIR)/ -p1 < tmp_key.patch
71
+	patch -d $(RUBY_DIR)/ -p1 < set_ecdh_curves.patch
71 72
 	cd $(RUBY_OPENSSL_EXT_DIR) && ruby extconf.rb
72 73
 
73 74
 $(RUBY_OPENSSL_EXT_DIR)/openssl.so: libs $(RUBY_OPENSSL_EXT_DIR)/Makefile

+ 34
- 9
lib/cryptcheck/tls/server.rb View File

@@ -1,6 +1,7 @@
1 1
 require 'socket'
2 2
 require 'openssl'
3 3
 require 'httparty'
4
+require 'awesome_print'
4 5
 
5 6
 module CryptCheck
6 7
 	module Tls
@@ -178,9 +179,22 @@ module CryptCheck
178 179
 				end
179 180
 			end
180 181
 
181
-			def ssl_client(method, ciphers = nil, &block)
182
+			# secp192r1 secp256r1
183
+			SUPPORTED_CURVES = %w(sect163k1 sect163r1 sect163r2 sect193r1 sect193r2
184
+									sect233k1 sect233r1 sect239k1 sect283k1 sect283r1
185
+									sect409k1 sect409r1 sect571k1 sect571r1 secp160k1
186
+									secp160r1 secp160r2 secp192k1 secp224k1
187
+									secp224r1 secp256k1 secp384r1 secp521r1)
188
+
189
+			def ssl_client(method, ciphers = nil, curves = nil, &block)
182 190
 				ssl_context         = ::OpenSSL::SSL::SSLContext.new method
183
-				ssl_context.ciphers = ciphers if ciphers
191
+				ssl_context.ciphers = ciphers.join ':' if ciphers
192
+
193
+				ssl_context.ecdh_curves = curves.join ':' if curves
194
+				#ssl_context.ecdh_auto = false
195
+				#ecdh = OpenSSL::PKey::EC.new('sect163r1').generate_key
196
+				#ssl_context.tmp_ecdh_callback = proc { ecdh }
197
+
184 198
 				Logger.trace { "Try #{method} connection with #{ciphers}" }
185 199
 				connect do |socket|
186 200
 					ssl_connect socket, ssl_context, method do |ssl_socket|
@@ -208,10 +222,10 @@ module CryptCheck
208 222
 			end
209 223
 
210 224
 			def prefered_cipher(method)
211
-				cipher = ssl_client(method, 'ALL:COMPLEMENTOFALL') { |s| Cipher.new method, s.cipher, s.tmp_key }
225
+				cipher = ssl_client(method, %w(ALL COMPLEMENTOFALL)) { |s| Cipher.new method, s.cipher, s.tmp_key }
212 226
 				Logger.info { "Prefered cipher for #{Tls.colorize method} : #{cipher.colorize}" }
213 227
 				cipher
214
-			rescue TLSException => e
228
+			rescue => e
215 229
 				Logger.debug { "Method #{Tls.colorize method} not supported : #{e}" }
216 230
 				nil
217 231
 			end
@@ -227,18 +241,18 @@ module CryptCheck
227 241
 
228 242
 			def available_ciphers(method)
229 243
 				context         = ::OpenSSL::SSL::SSLContext.new method
230
-				context.ciphers = 'ALL:COMPLEMENTOFALL'
244
+				context.ciphers = %w(ALL COMPLEMENTOFALL)
231 245
 				context.ciphers
232 246
 			end
233 247
 
234
-			def supported_cipher?(method, cipher)
235
-				dh = ssl_client method, [cipher] { |s| s.tmp_key }
248
+			def supported_cipher?(method, cipher, curves = nil)
249
+				dh = ssl_client(method, [cipher], curves) { |s| s.tmp_key }
236 250
 				@dh << dh if dh
237 251
 				cipher = Cipher.new method, cipher, dh
238 252
 				dh     = dh ? " (#{'DH'.colorize :green} : #{Tls.key_to_s dh})" : ''
239 253
 				Logger.info { "#{Tls.colorize method} / #{cipher.colorize} : Supported#{dh}" }
240 254
 				cipher
241
-			rescue TLSException => e
255
+			rescue => e
242 256
 				cipher = Cipher.new method, cipher
243 257
 				Logger.debug { "#{Tls.colorize method} / #{cipher.colorize} : Not supported (#{e})" }
244 258
 				nil
@@ -249,7 +263,18 @@ module CryptCheck
249 263
 				@supported_ciphers = {}
250 264
 				EXISTING_METHODS.each do |method|
251 265
 					next unless SUPPORTED_METHODS.include? method and @prefered_ciphers[method]
252
-					supported_ciphers = available_ciphers(method).collect { |c| supported_cipher? method, c }.reject { |c| c.nil? }
266
+					available_ciphers = available_ciphers method
267
+					available_ciphers = available_ciphers.inject [] do |cs, c|
268
+						cipher = Cipher.new method, c
269
+						if cipher.ecdhe?
270
+							c = SUPPORTED_CURVES.collect { |ec| [method, c.first, [ec]] }
271
+						else
272
+							c = [[method, c.first]]
273
+						end
274
+						cs + c
275
+					end
276
+
277
+					supported_ciphers = available_ciphers.collect { |c| supported_cipher? *c }.reject { |c| c.nil? }
253 278
 					Logger.info { '' } unless supported_ciphers.empty?
254 279
 					@supported_ciphers[method] = supported_ciphers
255 280
 				end

+ 427
- 0
set_ecdh_curves.patch View File

@@ -0,0 +1,427 @@
1
+diff -ur a/ext/openssl/deprecation.rb b/ext/openssl/deprecation.rb
2
+--- a/ext/openssl/deprecation.rb	2016-11-11 14:41:20.866580715 +0100
3
++++ b/ext/openssl/deprecation.rb	2016-11-11 14:41:37.570583620 +0100
4
+@@ -19,4 +19,9 @@
5
+     have_func(func, header, deprecated_warning_flag) and
6
+       have_header(header, nil, deprecated_warning_flag)
7
+   end
8
++
9
++  def self.check_func_or_macro(func, header)
10
++    check_func(func, header) or
11
++      have_macro(func, header) && $defs.push("-DHAVE_#{func.upcase}")
12
++  end
13
+ end
14
+diff -ur a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
15
+--- a/ext/openssl/extconf.rb	2016-11-11 12:05:50.490942389 +0100
16
++++ b/ext/openssl/extconf.rb	2016-11-11 12:08:46.323026500 +0100
17
+@@ -93,6 +93,7 @@
18
+ have_func("X509_NAME_hash_old")
19
+ have_func("X509_STORE_get_ex_data")
20
+ have_func("X509_STORE_set_ex_data")
21
++OpenSSL.check_func_or_macro("SSL_CTX_set_tmp_ecdh_callback", "openssl/ssl.h") # removed
22
+ have_func("OBJ_NAME_do_all_sorted")
23
+ have_func("SSL_SESSION_get_id")
24
+ have_func("SSL_SESSION_cmp")
25
+@@ -109,7 +110,10 @@
26
+ have_func("TLSv1_2_method")
27
+ have_func("TLSv1_2_server_method")
28
+ have_func("TLSv1_2_client_method")
29
++have_func("EC_curve_nist2nid")
30
+ have_func("SSL_CTX_set_alpn_select_cb")
31
++OpenSSL.check_func_or_macro("SSL_CTX_set1_curves_list", "openssl/ssl.h")
32
++OpenSSL.check_func_or_macro("SSL_CTX_set_ecdh_auto", "openssl/ssl.h")
33
+ have_func("SSL_CTX_set_next_proto_select_cb")
34
+ unless have_func("SSL_set_tlsext_host_name", ['openssl/ssl.h'])
35
+   have_macro("SSL_set_tlsext_host_name", ['openssl/ssl.h']) && $defs.push("-DHAVE_SSL_SET_TLSEXT_HOST_NAME")
36
+diff -ur a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c
37
+--- a/ext/openssl/openssl_missing.c	2016-11-11 12:05:50.858942585 +0100
38
++++ b/ext/openssl/openssl_missing.c	2016-11-11 12:10:17.575063207 +0100
39
+@@ -34,6 +34,43 @@
40
+ #endif /* HAVE_HMAC_CTX_COPY */
41
+ #endif /* NO_HMAC */
42
+ 
43
++/* added in 1.0.2 */
44
++#if !defined(OPENSSL_NO_EC)
45
++#if !defined(HAVE_EC_CURVE_NIST2NID)
46
++static struct {
47
++    const char *name;
48
++    int nid;
49
++} nist_curves[] = {
50
++    {"B-163", NID_sect163r2},
51
++    {"B-233", NID_sect233r1},
52
++    {"B-283", NID_sect283r1},
53
++    {"B-409", NID_sect409r1},
54
++    {"B-571", NID_sect571r1},
55
++    {"K-163", NID_sect163k1},
56
++    {"K-233", NID_sect233k1},
57
++    {"K-283", NID_sect283k1},
58
++    {"K-409", NID_sect409k1},
59
++    {"K-571", NID_sect571k1},
60
++    {"P-192", NID_X9_62_prime192v1},
61
++    {"P-224", NID_secp224r1},
62
++    {"P-256", NID_X9_62_prime256v1},
63
++    {"P-384", NID_secp384r1},
64
++    {"P-521", NID_secp521r1}
65
++};
66
++
67
++int
68
++EC_curve_nist2nid(const char *name)
69
++{
70
++    size_t i;
71
++    for (i = 0; i < (sizeof(nist_curves) / sizeof(nist_curves[0])); i++) {
72
++	if (!strcmp(nist_curves[i].name, name))
73
++	    return nist_curves[i].nid;
74
++    }
75
++    return NID_undef;
76
++}
77
++#endif
78
++#endif
79
++
80
+ #if !defined(HAVE_X509_STORE_SET_EX_DATA)
81
+ int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data)
82
+ {
83
+diff -ur a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
84
+--- a/ext/openssl/openssl_missing.h	2016-11-11 12:05:51.210942773 +0100
85
++++ b/ext/openssl/openssl_missing.h	2016-11-11 12:10:49.307074964 +0100
86
+@@ -70,6 +70,12 @@
87
+ void HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in);
88
+ #endif
89
+ 
90
++#if !defined(OPENSSL_NO_EC)
91
++#if !defined(HAVE_EC_CURVE_NIST2NID)
92
++int EC_curve_nist2nid(const char *);
93
++#endif
94
++#endif
95
++
96
+ #if !defined(HAVE_HMAC_CTX_CLEANUP)
97
+ void HMAC_CTX_cleanup(HMAC_CTX *ctx);
98
+ #endif
99
+diff -ur a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
100
+--- a/ext/openssl/ossl_ssl.c	2016-11-11 12:05:51.590942974 +0100
101
++++ b/ext/openssl/ossl_ssl.c	2016-11-11 14:47:24.746639981 +0100
102
+@@ -161,6 +161,18 @@
103
+     RTYPEDDATA_DATA(obj) = ctx;
104
+     SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)obj);
105
+ 
106
++#if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
107
++    /* We use SSL_CTX_set1_curves_list() to specify the curve used in ECDH. It
108
++     * allows to specify multiple curve names and OpenSSL will select
109
++     * automatically from them. In OpenSSL 1.0.2, the automatic selection has to
110
++     * be enabled explicitly. But OpenSSL 1.1.0 removed the knob and it is
111
++     * always enabled. To uniform the behavior, we enable the automatic
112
++     * selection also in 1.0.2. Users can still disable ECDH by removing ECDH
113
++     * cipher suites by SSLContext#ciphers=. */
114
++    if (!SSL_CTX_set_ecdh_auto(ctx, 1))
115
++        ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
116
++#endif
117
++
118
+     return obj;
119
+ }
120
+ 
121
+@@ -711,19 +723,33 @@
122
+ #endif
123
+ 
124
+ #if !defined(OPENSSL_NO_EC)
125
+-    if (RTEST(ossl_sslctx_get_tmp_ecdh_cb(self))){
126
+-	SSL_CTX_set_tmp_ecdh_callback(ctx, ossl_tmp_ecdh_callback);
127
+-    }
128
+-#endif
129
++    /* We added SSLContext#tmp_ecdh_callback= in Ruby 2.3.0,
130
++     * but SSL_CTX_set_tmp_ecdh_callback() was removed in OpenSSL 1.1.0. */
131
++    if (RTEST(ossl_sslctx_get_tmp_ecdh_cb(self))) {
132
++# if defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
133
++        rb_warn("#tmp_ecdh_callback= is deprecated; use #ecdh_curves= instead");
134
++        SSL_CTX_set_tmp_ecdh_callback(ctx, ossl_tmp_ecdh_callback);
135
++#  if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
136
++        /* tmp_ecdh_callback and ecdh_auto conflict; OpenSSL ignores
137
++        * tmp_ecdh_callback. So disable ecdh_auto. */
138
++        if (!SSL_CTX_set_ecdh_auto(ctx, 0))
139
++            ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
140
++#  endif
141
++# else
142
++    ossl_raise(eSSLError, "OpenSSL does not support tmp_ecdh_callback; "
143
++           "use #ecdh_curves= instead");
144
++# endif
145
++	}
146
++#endif /* OPENSSL_NO_EC */
147
+ 
148
+     val = ossl_sslctx_get_cert_store(self);
149
+     if(!NIL_P(val)){
150
+-	/*
151
+-         * WORKAROUND:
152
+-	 *   X509_STORE can count references, but
153
+-	 *   X509_STORE_free() doesn't care it.
154
+-	 *   So we won't increment it but mark it by ex_data.
155
+-	 */
156
++        /*
157
++        * WORKAROUND:
158
++        *   X509_STORE can count references, but
159
++        *   X509_STORE_free() doesn't care it.
160
++        *   So we won't increment it but mark it by ex_data.
161
++        */
162
+         store = GetX509StorePtr(val); /* NO NEED TO DUP */
163
+         SSL_CTX_set_cert_store(ctx, store);
164
+         SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1);
165
+@@ -731,7 +757,7 @@
166
+ 
167
+     val = ossl_sslctx_get_extra_cert(self);
168
+     if(!NIL_P(val)){
169
+-	rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
170
++        rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
171
+     }
172
+ 
173
+     /* private key may be bundled in certificate file. */
174
+@@ -755,22 +781,21 @@
175
+ 
176
+     val = ossl_sslctx_get_client_ca(self);
177
+     if(!NIL_P(val)){
178
+-	if (RB_TYPE_P(val, T_ARRAY)) {
179
+-	    for(i = 0; i < RARRAY_LEN(val); i++){
180
+-		client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
181
+-        	if (!SSL_CTX_add_client_CA(ctx, client_ca)){
182
+-		    /* Copies X509_NAME => FREE it. */
183
+-        	    ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
184
+-        	}
185
+-	    }
186
+-        }
187
+-	else{
188
+-	    client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
189
++        if (RB_TYPE_P(val, T_ARRAY)) {
190
++            for(i = 0; i < RARRAY_LEN(val); i++){
191
++                client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
192
++                if (!SSL_CTX_add_client_CA(ctx, client_ca)){
193
++                    /* Copies X509_NAME => FREE it. */
194
++                    ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
195
++                }
196
++	        }
197
++        } else {
198
++            client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
199
+             if (!SSL_CTX_add_client_CA(ctx, client_ca)){
200
+-		/* Copies X509_NAME => FREE it. */
201
+-        	ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
202
++                /* Copies X509_NAME => FREE it. */
203
++                ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
204
+             }
205
+-	}
206
++	    }
207
+     }
208
+ 
209
+     val = ossl_sslctx_get_ca_file(self);
210
+@@ -778,15 +803,15 @@
211
+     val = ossl_sslctx_get_ca_path(self);
212
+     ca_path = NIL_P(val) ? NULL : StringValuePtr(val);
213
+     if(ca_file || ca_path){
214
+-	if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
215
+-	    rb_warning("can't set verify locations");
216
++        if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
217
++            rb_warning("can't set verify locations");
218
+     }
219
+ 
220
+     val = ossl_sslctx_get_verify_mode(self);
221
+     verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
222
+     SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
223
+     if (RTEST(ossl_sslctx_get_client_cert_cb(self)))
224
+-	SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
225
++        SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
226
+ 
227
+     val = ossl_sslctx_get_timeout(self);
228
+     if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));
229
+@@ -797,26 +822,26 @@
230
+ #ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB
231
+     val = rb_iv_get(self, "@npn_protocols");
232
+     if (!NIL_P(val)) {
233
+-	rb_iv_set(self, "@_protocols", ssl_encode_npn_protocols(val));
234
+-	SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *) self);
235
+-	OSSL_Debug("SSL NPN advertise callback added");
236
++        rb_iv_set(self, "@_protocols", ssl_encode_npn_protocols(val));
237
++        SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *) self);
238
++        OSSL_Debug("SSL NPN advertise callback added");
239
+     }
240
+     if (RTEST(rb_iv_get(self, "@npn_select_cb"))) {
241
+-	SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
242
+-	OSSL_Debug("SSL NPN select callback added");
243
++        SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
244
++        OSSL_Debug("SSL NPN select callback added");
245
+     }
246
+ #endif
247
+ 
248
+ #ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
249
+     val = rb_iv_get(self, "@alpn_protocols");
250
+     if (!NIL_P(val)) {
251
+-	VALUE rprotos = ssl_encode_npn_protocols(val);
252
+-	SSL_CTX_set_alpn_protos(ctx, (const unsigned char *)StringValueCStr(rprotos), RSTRING_LENINT(rprotos));
253
+-	OSSL_Debug("SSL ALPN values added");
254
++        VALUE rprotos = ssl_encode_npn_protocols(val);
255
++        SSL_CTX_set_alpn_protos(ctx, (const unsigned char *)StringValueCStr(rprotos), RSTRING_LENINT(rprotos));
256
++        OSSL_Debug("SSL ALPN values added");
257
+     }
258
+     if (RTEST(rb_iv_get(self, "@alpn_select_cb"))) {
259
+-	SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
260
+-	OSSL_Debug("SSL ALPN select callback added");
261
++        SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
262
++        OSSL_Debug("SSL ALPN select callback added");
263
+     }
264
+ #endif
265
+ 
266
+@@ -824,31 +849,31 @@
267
+ 
268
+     val = ossl_sslctx_get_sess_id_ctx(self);
269
+     if (!NIL_P(val)){
270
+-	StringValue(val);
271
+-	if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
272
+-					    RSTRING_LENINT(val))){
273
+-	    ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
274
+-	}
275
++        StringValue(val);
276
++        if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
277
++                RSTRING_LENINT(val))){
278
++            ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
279
++        }
280
+     }
281
+ 
282
+     if (RTEST(rb_iv_get(self, "@session_get_cb"))) {
283
+-	SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
284
+-	OSSL_Debug("SSL SESSION get callback added");
285
++        SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
286
++        OSSL_Debug("SSL SESSION get callback added");
287
+     }
288
+     if (RTEST(rb_iv_get(self, "@session_new_cb"))) {
289
+-	SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
290
+-	OSSL_Debug("SSL SESSION new callback added");
291
++        SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
292
++        OSSL_Debug("SSL SESSION new callback added");
293
+     }
294
+     if (RTEST(rb_iv_get(self, "@session_remove_cb"))) {
295
+-	SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
296
+-	OSSL_Debug("SSL SESSION remove callback added");
297
++        SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
298
++        OSSL_Debug("SSL SESSION remove callback added");
299
+     }
300
+ 
301
+ #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
302
+     val = rb_iv_get(self, "@servername_cb");
303
+     if (!NIL_P(val)) {
304
+         SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
305
+-	OSSL_Debug("SSL TLSEXT servername callback added");
306
++        OSSL_Debug("SSL TLSEXT servername callback added");
307
+     }
308
+ #endif
309
+ 
310
+@@ -953,6 +978,87 @@
311
+     return v;
312
+ }
313
+ 
314
++#if !defined(OPENSSL_NO_EC)
315
++/*
316
++ * call-seq:
317
++ *    ctx.ecdh_curves = curve_list -> curve_list
318
++ *
319
++ * Sets the list of "supported elliptic curves" for this context.
320
++ *
321
++ * For a TLS client, the list is directly used in the Supported Elliptic Curves
322
++ * Extension. For a server, the list is used by OpenSSL to determine the set of
323
++ * shared curves. OpenSSL will pick the most appropriate one from it.
324
++ *
325
++ * Note that this works differently with old OpenSSL (<= 1.0.1). Only one curve
326
++ * can be set, and this has no effect for TLS clients.
327
++ *
328
++ * === Example
329
++ *   ctx1 = OpenSSL::SSL::SSLContext.new
330
++ *   ctx1.ecdh_curves = "X25519:P-256:P-224"
331
++ *   svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx1)
332
++ *   Thread.new { svr.accept }
333
++ *
334
++ *   ctx2 = OpenSSL::SSL::SSLContext.new
335
++ *   ctx2.ecdh_curves = "P-256"
336
++ *   cli = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx2)
337
++ *   cli.connect
338
++ *
339
++ *   p cli.tmp_key.group.curve_name
340
++ *   # => "prime256v1" (is an alias for NIST P-256)
341
++ */
342
++static VALUE
343
++ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg)
344
++{
345
++    SSL_CTX *ctx;
346
++
347
++    rb_check_frozen(self);
348
++    GetSSLCTX(self, ctx);
349
++    StringValueCStr(arg);
350
++
351
++#if defined(HAVE_SSL_CTX_SET1_CURVES_LIST)
352
++    if (!SSL_CTX_set1_curves_list(ctx, RSTRING_PTR(arg)))
353
++	ossl_raise(eSSLError, NULL);
354
++#else
355
++    /* OpenSSL does not have SSL_CTX_set1_curves_list()... Fallback to
356
++     * SSL_CTX_set_tmp_ecdh(). So only the first curve is used. */
357
++    {
358
++	VALUE curve, splitted;
359
++	EC_KEY *ec;
360
++	int nid;
361
++
362
++	splitted = rb_str_split(arg, ":");
363
++	if (!RARRAY_LEN(splitted))
364
++	    ossl_raise(eSSLError, "invalid input format");
365
++	curve = RARRAY_AREF(splitted, 0);
366
++	StringValueCStr(curve);
367
++
368
++	/* SSL_CTX_set1_curves_list() accepts NIST names */
369
++	nid = EC_curve_nist2nid(RSTRING_PTR(curve));
370
++	if (nid == NID_undef)
371
++	    nid = OBJ_txt2nid(RSTRING_PTR(curve));
372
++	if (nid == NID_undef)
373
++	    ossl_raise(eSSLError, "unknown curve name");
374
++
375
++	ec = EC_KEY_new_by_curve_name(nid);
376
++	if (!ec)
377
++	    ossl_raise(eSSLError, NULL);
378
++	EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
379
++	SSL_CTX_set_tmp_ecdh(ctx, ec);
380
++# if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
381
++	/* tmp_ecdh and ecdh_auto conflict. tmp_ecdh is ignored when ecdh_auto
382
++	 * is enabled. So disable ecdh_auto. */
383
++	if (!SSL_CTX_set_ecdh_auto(ctx, 0))
384
++	    ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
385
++# endif
386
++    }
387
++#endif
388
++
389
++    return arg;
390
++}
391
++#else
392
++#define ossl_sslctx_set_ecdh_curves rb_f_notimplement
393
++#endif
394
++
395
+ /*
396
+  *  call-seq:
397
+  *     ctx.session_add(session) -> true | false
398
+@@ -2075,6 +2181,7 @@
399
+      */
400
+     rb_attr(cSSLContext, rb_intern("client_cert_cb"), 1, 1, Qfalse);
401
+ 
402
++#if defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
403
+     /*
404
+      * A callback invoked when ECDH parameters are required.
405
+      *
406
+@@ -2082,10 +2189,11 @@
407
+      * flag indicating the use of an export cipher and the keylength
408
+      * required.
409
+      *
410
+-     * The callback must return an OpenSSL::PKey::EC instance of the correct
411
+-     * key length.
412
++     * The callback is deprecated. This does not work with recent versions of
413
++     * OpenSSL. Use OpenSSL::SSL::SSLContext#ecdh_curves= instead.
414
+      */
415
+     rb_attr(cSSLContext, rb_intern("tmp_ecdh_callback"), 1, 1, Qfalse);
416
++#endif
417
+ 
418
+     /*
419
+      * Sets the context in which a session can be reused.  This allows
420
+@@ -2221,6 +2329,7 @@
421
+     rb_define_method(cSSLContext, "ssl_version=", ossl_sslctx_set_ssl_version, 1);
422
+     rb_define_method(cSSLContext, "ciphers",     ossl_sslctx_get_ciphers, 0);
423
+     rb_define_method(cSSLContext, "ciphers=",    ossl_sslctx_set_ciphers, 1);
424
++    rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1);
425
+ 
426
+     rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
427
+ 

+ 7
- 7
tmp_key.patch View File

@@ -14,7 +14,7 @@ diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
14 14
 index 4075d6f..982e011 100644
15 15
 --- a/ext/openssl/ossl_ssl.c
16 16
 +++ b/ext/openssl/ossl_ssl.c
17
-@@ -1910,6 +1910,25 @@ ossl_ssl_alpn_protocol(VALUE self)
17
+@@ -1911,6 +1911,25 @@ ossl_ssl_alpn_protocol(VALUE self)
18 18
  	return rb_str_new((const char *) out, outlen);
19 19
  }
20 20
  # endif
@@ -38,9 +38,9 @@ index 4075d6f..982e011 100644
38 38
 +}
39 39
 +# endif /* defined(HAVE_SSL_GET_SERVER_TMP_KEY) */
40 40
  #endif /* !defined(OPENSSL_NO_SOCK) */
41
- 
41
+
42 42
  void
43
-@@ -2304,6 +2323,9 @@ Init_ossl_ssl(void)
43
+@@ -2305,6 +2324,9 @@ Init_ossl_ssl(void)
44 44
      rb_define_method(cSSLSocket, "session=",    ossl_ssl_set_session, 1);
45 45
      rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0);
46 46
      rb_define_method(cSSLSocket, "client_ca", ossl_ssl_get_client_ca_list, 0);
@@ -54,10 +54,10 @@ diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
54 54
 index 58fcc08..3ce4e21 100644
55 55
 --- a/test/openssl/test_ssl.rb
56 56
 +++ b/test/openssl/test_ssl.rb
57
-@@ -1167,6 +1167,29 @@ def test_sync_close_without_connect
57
+@@ -1169,6 +1169,29 @@ def test_sync_close_without_connect
58 58
      }
59 59
    end
60
- 
60
+
61 61
 +  def test_get_ephemeral_key
62 62
 +    return unless OpenSSL::SSL::SSLSocket.method_defined?(:tmp_key)
63 63
 +    ciphers = {
@@ -82,7 +82,7 @@ index 58fcc08..3ce4e21 100644
82 82
 +  end
83 83
 +
84 84
    private
85
- 
85
+
86 86
    def start_server_version(version, ctx_proc=nil, server_proc=nil, &blk)
87 87
 diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb
88 88
 index 0802c1b..c081e4f 100644
@@ -95,4 +95,4 @@ index 0802c1b..c081e4f 100644
95 95
 +        ctx.tmp_ecdh_callback = proc { OpenSSL::TestUtils::TEST_KEY_EC_P256V1 }
96 96
          ctx.verify_mode = verify_mode
97 97
          ctx_proc.call(ctx) if ctx_proc
98
- 
98
+

Loading…
Cancel
Save