Skip to content

Commit b053e6b

Browse files
committed
Introduce OpenSSL::SSL::Context::Server, OpenSSL::SSL::Context::Client,
OpenSSL::SSL::Socket::Server and OpenSSL::SSL::Socket::Client
1 parent f0c3456 commit b053e6b

File tree

8 files changed

+134
-117
lines changed

8 files changed

+134
-117
lines changed

spec/std/http/client/client_spec.cr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ module HTTP
6161
end
6262

6363
it "keeps context" do
64-
ctx = OpenSSL::SSL::Context.new_for_client
64+
ctx = OpenSSL::SSL::Context::Client.new
6565
cl = Client.new(URI.parse("https://example.com"), ctx)
6666
cl.ssl.should be(ctx)
6767
end
6868

6969
it "doesn't take context for HTTP" do
70-
ctx = OpenSSL::SSL::Context.new_for_client
70+
ctx = OpenSSL::SSL::Context::Client.new
7171
expect_raises(ArgumentError, "SSL context given") do
7272
Client.new(URI.parse("http://example.com"), ctx)
7373
end

spec/std/http/server/server_spec.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module HTTP
3232

3333
describe Response do
3434
it "creates default ssl context" do
35-
HTTP::Server.default_ssl_context.should be_a(OpenSSL::SSL::Context)
35+
HTTP::Server.default_ssl_context.should be_a(OpenSSL::SSL::Context::Server)
3636
end
3737

3838
it "closes" do

spec/std/openssl/ssl/context_spec.cr

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,91 +3,91 @@ require "openssl"
33

44
describe OpenSSL::SSL::Context do
55
it "new_for_client" do
6-
ssl_context = OpenSSL::SSL::Context.new_for_client
6+
ssl_context = OpenSSL::SSL::Context::Client.new
77
ssl_context.verify_mode.should eq(OpenSSL::SSL::VerifyMode::PEER)
8-
OpenSSL::SSL::Context.new_for_client(LibSSL.tlsv1_method)
8+
OpenSSL::SSL::Context::Client.new(LibSSL.tlsv1_method)
99
end
1010

1111
it "new_for_server" do
12-
ssl_context = OpenSSL::SSL::Context.new_for_server
12+
ssl_context = OpenSSL::SSL::Context::Server.new
1313
ssl_context.verify_mode.should eq(OpenSSL::SSL::VerifyMode::NONE)
14-
OpenSSL::SSL::Context.new_for_server(LibSSL.tlsv1_method)
14+
OpenSSL::SSL::Context::Server.new(LibSSL.tlsv1_method)
1515
end
1616

1717
it "sets certificate chain" do
18-
ssl_context = OpenSSL::SSL::Context.new_for_client
18+
ssl_context = OpenSSL::SSL::Context::Client.new
1919
ssl_context.certificate_chain = File.join(__DIR__, "openssl.crt")
2020
end
2121

2222
it "fails to set certificate chain" do
23-
ssl_context = OpenSSL::SSL::Context.new_for_client
23+
ssl_context = OpenSSL::SSL::Context::Client.new
2424
expect_raises(OpenSSL::Error) { ssl_context.certificate_chain = File.join(__DIR__, "unknown.crt") }
2525
expect_raises(OpenSSL::Error) { ssl_context.certificate_chain = __FILE__ }
2626
end
2727

2828
it "sets private key" do
29-
ssl_context = OpenSSL::SSL::Context.new_for_client
29+
ssl_context = OpenSSL::SSL::Context::Client.new
3030
ssl_context.private_key = File.join(__DIR__, "openssl.key")
3131
end
3232

3333
it "fails to set private key" do
34-
ssl_context = OpenSSL::SSL::Context.new_for_client
34+
ssl_context = OpenSSL::SSL::Context::Client.new
3535
expect_raises(OpenSSL::Error) { ssl_context.private_key = File.join(__DIR__, "unknown.key") }
3636
expect_raises(OpenSSL::Error) { ssl_context.private_key = __FILE__ }
3737
end
3838

3939
it "sets ciphers" do
4040
ciphers = "EDH+aRSA DES-CBC3-SHA !RC4"
41-
ssl_context = OpenSSL::SSL::Context.new_for_client
41+
ssl_context = OpenSSL::SSL::Context::Client.new
4242
(ssl_context.ciphers = ciphers).should eq(ciphers)
4343
end
4444

4545
it "adds temporary ecdh curve (P-256)" do
46-
ssl_context = OpenSSL::SSL::Context.new_for_client
46+
ssl_context = OpenSSL::SSL::Context::Client.new
4747
ssl_context.set_tmp_ecdh_key
4848
end
4949

5050
it "adds options" do
51-
ssl_context = OpenSSL::SSL::Context.new_for_client
51+
ssl_context = OpenSSL::SSL::Context::Client.new
5252
ssl_context.remove_options(ssl_context.options) # reset
5353
ssl_context.add_options(LibSSL::Options::ALL).should eq(LibSSL::Options::ALL)
5454
ssl_context.add_options(LibSSL::Options::NO_SSLV2 | LibSSL::Options::NO_SSLV3)
5555
.should eq(LibSSL::Options::ALL | LibSSL::Options::NO_SSLV2 | LibSSL::Options::NO_SSLV3)
5656
end
5757

5858
it "removes options" do
59-
ssl_context = OpenSSL::SSL::Context.new_for_client
59+
ssl_context = OpenSSL::SSL::Context::Client.new
6060
ssl_context.add_options(LibSSL::Options::ALL | LibSSL::Options::NO_SSLV2)
6161
ssl_context.remove_options(LibSSL::Options::ALL).should eq(LibSSL::Options::NO_SSLV2)
6262
end
6363

6464
it "returns options" do
65-
ssl_context = OpenSSL::SSL::Context.new_for_client
65+
ssl_context = OpenSSL::SSL::Context::Client.new
6666
ssl_context.add_options(LibSSL::Options::ALL | LibSSL::Options::NO_SSLV2)
6767
ssl_context.options.should eq(LibSSL::Options::ALL | LibSSL::Options::NO_SSLV2)
6868
end
6969

7070
it "adds modes" do
71-
ssl_context = OpenSSL::SSL::Context.new_for_client
71+
ssl_context = OpenSSL::SSL::Context::Client.new
7272
ssl_context.add_modes(LibSSL::Modes::AUTO_RETRY).should eq(LibSSL::Modes::AUTO_RETRY)
7373
ssl_context.add_modes(LibSSL::Modes::RELEASE_BUFFERS)
7474
.should eq(LibSSL::Modes::AUTO_RETRY | LibSSL::Modes::RELEASE_BUFFERS)
7575
end
7676

7777
it "removes modes" do
78-
ssl_context = OpenSSL::SSL::Context.new_for_client
78+
ssl_context = OpenSSL::SSL::Context::Client.new
7979
ssl_context.add_modes(LibSSL::Modes::AUTO_RETRY | LibSSL::Modes::RELEASE_BUFFERS)
8080
ssl_context.remove_modes(LibSSL::Modes::AUTO_RETRY).should eq(LibSSL::Modes::RELEASE_BUFFERS)
8181
end
8282

8383
it "returns modes" do
84-
ssl_context = OpenSSL::SSL::Context.new_for_client
84+
ssl_context = OpenSSL::SSL::Context::Client.new
8585
ssl_context.add_modes(LibSSL::Modes::AUTO_RETRY | LibSSL::Modes::RELEASE_BUFFERS)
8686
ssl_context.modes.should eq(LibSSL::Modes::AUTO_RETRY | LibSSL::Modes::RELEASE_BUFFERS)
8787
end
8888

8989
it "sets the verify mode" do
90-
ssl_context = OpenSSL::SSL::Context.new_for_client
90+
ssl_context = OpenSSL::SSL::Context::Client.new
9191
ssl_context.verify_mode = OpenSSL::SSL::VerifyMode::NONE
9292
ssl_context.verify_mode.should eq(OpenSSL::SSL::VerifyMode::NONE)
9393
ssl_context.verify_mode = OpenSSL::SSL::VerifyMode::PEER
@@ -96,7 +96,7 @@ describe OpenSSL::SSL::Context do
9696

9797
pending "alpn_protocol=" do
9898
# requires OpenSSL 1.0.2+
99-
ssl_context = OpenSSL::SSL::Context.new_for_client
99+
ssl_context = OpenSSL::SSL::Context::Client.new
100100
ssl_context.alpn_protocol = "h2"
101101
end
102102
end

src/http/client/client.cr

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,18 @@ class HTTP::Client
6969
# ```
7070
getter port : Int32
7171

72-
# If this client uses SSL, returns its `OpenSSL::SSL::Context`, raises otherwise.
72+
# If this client uses SSL, returns its `OpenSSL::SSL::Context::Client`, raises otherwise.
7373
#
7474
# Changes made after the initial request will have no effect.
7575
#
7676
# ```
7777
# client = HTTP::Client.new "www.example.com", ssl: true
78-
# client.ssl # => #<OpenSSL::SSL::Context ...>
78+
# client.ssl # => #<OpenSSL::SSL::Context::Client ...>
7979
# ```
8080
ifdef without_openssl
8181
getter! ssl : Nil
8282
else
83-
getter! ssl : OpenSSL::SSL::Context?
83+
getter! ssl : OpenSSL::SSL::Context::Client?
8484
end
8585

8686
# Whether automatic compression/decompression is enabled.
@@ -99,7 +99,7 @@ class HTTP::Client
9999
# Creates a new HTTP client with the given *host*, *port* and *ssl*
100100
# configurations. If no port is given, the default one will
101101
# be used depending on the *ssl* arguments: 80 for if *ssl* is `false`,
102-
# 443 if *ssl* is truthy. If *ssl* is `true` a new `OpenSSL::SSL::Context` will
102+
# 443 if *ssl* is truthy. If *ssl* is `true` a new `OpenSSL::SSL::Context::Client` will
103103
# be used, else the given one. In any case the active context can be accessed through `ssl`.
104104
ifdef without_openssl
105105
def initialize(@host, port = nil, ssl : Bool = false)
@@ -112,11 +112,11 @@ class HTTP::Client
112112
@compress = true
113113
end
114114
else
115-
def initialize(@host, port = nil, ssl : Bool | OpenSSL::SSL::Context = false)
115+
def initialize(@host, port = nil, ssl : Bool | OpenSSL::SSL::Context::Client = false)
116116
@ssl = case ssl
117117
when true
118-
OpenSSL::SSL::Context.new_for_client
119-
when OpenSSL::SSL::Context
118+
OpenSSL::SSL::Context::Client.new
119+
when OpenSSL::SSL::Context::Client
120120
ssl
121121
when false
122122
nil
@@ -530,7 +530,7 @@ class HTTP::Client
530530

531531
ifdef !without_openssl
532532
if ssl = @ssl
533-
ssl_socket = OpenSSL::SSL::Socket.new(socket, context: ssl, sync_close: true, hostname: @host)
533+
ssl_socket = OpenSSL::SSL::Socket::Client.new(socket, context: ssl, sync_close: true, hostname: @host)
534534
@socket = socket = ssl_socket
535535
end
536536
end
@@ -574,18 +574,18 @@ class HTTP::Client
574574
end
575575
end
576576
else
577-
protected def self.ssl_flag(uri, context : OpenSSL::SSL::Context?)
577+
protected def self.ssl_flag(uri, context : OpenSSL::SSL::Context::Client?)
578578
scheme = uri.scheme
579579
case {scheme, context}
580580
when {nil, _}
581581
raise ArgumentError.new("missing scheme: #{uri}")
582582
when {"http", nil}
583583
false
584-
when {"http", OpenSSL::SSL::Context}
584+
when {"http", OpenSSL::SSL::Context::Client}
585585
raise ArgumentError.new("SSL context given for HTTP URI")
586586
when {"https", nil}
587587
true
588-
when {"https", OpenSSL::SSL::Context}
588+
when {"https", OpenSSL::SSL::Context::Client}
589589
context
590590
else
591591
raise ArgumentError.new "Unsupported scheme: #{scheme}"

src/http/server/server.cr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ require "../common"
8989
# ```
9090
class HTTP::Server
9191
ifdef !without_openssl
92-
property ssl : OpenSSL::SSL::Context?
92+
property ssl : OpenSSL::SSL::Context::Server?
9393

9494
def self.default_ssl_context : OpenSSL::SSL::Context
95-
ctx = OpenSSL::SSL::Context.new_for_server
95+
ctx = OpenSSL::SSL::Context::Server.new
9696
ctx.add_options(
9797
LibSSL::Options::ALL |
9898
LibSSL::Options::NO_SSLV2 |
@@ -176,7 +176,7 @@ class HTTP::Server
176176

177177
ifdef !without_openssl
178178
if ssl = @ssl
179-
io = OpenSSL::SSL::Socket.new(io, :server, ssl, sync_close: true)
179+
io = OpenSSL::SSL::Socket::Server.new(io, ssl, sync_close: true)
180180
end
181181
end
182182

src/http/web_socket/protocol.cr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,11 @@ class HTTP::WebSocket::Protocol
233233
ifdef !without_openssl
234234
if ssl
235235
if ssl.is_a?(Bool) # true, but we want to get rid of the union
236-
context = OpenSSL::SSL::Context.new_for_client
236+
context = OpenSSL::SSL::Context::Client.new
237237
else
238238
context = ssl
239239
end
240-
socket = OpenSSL::SSL::Socket.new(socket, context: context, sync_close: true)
240+
socket = OpenSSL::SSL::Socket::Client.new(socket, context: context, sync_close: true)
241241
end
242242
end
243243

src/openssl/ssl/context.cr

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,51 @@
1-
class OpenSSL::SSL::Context
2-
# Generates a new SSL context with sane defaults for a client connection.
3-
#
4-
# By default it defaults to the `SSLv23_method` which actually means that
5-
# OpenSSL will negotiate the TLS or SSL protocol to use with the remote
6-
# endpoint.
7-
#
8-
# Don't change the method unless you must restrict a specific protocol to be
9-
# used (eg: TLSv1.2) and nothing else. You should specify options to disable
10-
# specific protocols, yet allow to negotiate from various other ones. For
11-
# example the following snippet will enable the TLSv1, TLSv1.1 and TLSv1.2
12-
# protocols but disable the deprecated SSLv2 and SSLv3 protocols:
13-
#
14-
# ```
15-
# ssl_context = OpenSSL::SSL::Context.new_for_client
16-
# ssl_context.options = LibSSL::Options::NO_SSLV2 | LibSSL::Options::NO_SSLV3
17-
# ```
18-
def self.new_for_client(method : LibSSL::SSLMethod = LibSSL.sslv23_method)
19-
new(method).tap do |context|
20-
context.verify_mode = OpenSSL::SSL::VerifyMode::PEER
1+
abstract class OpenSSL::SSL::Context
2+
class Client < Context
3+
# Generates a new SSL context with sane defaults for a client connection.
4+
#
5+
# By default it defaults to the `SSLv23_method` which actually means that
6+
# OpenSSL will negotiate the TLS or SSL protocol to use with the remote
7+
# endpoint.
8+
#
9+
# Don't change the method unless you must restrict a specific protocol to be
10+
# used (eg: TLSv1.2) and nothing else. You should specify options to disable
11+
# specific protocols, yet allow to negotiate from various other ones. For
12+
# example the following snippet will enable the TLSv1, TLSv1.1 and TLSv1.2
13+
# protocols but disable the deprecated SSLv2 and SSLv3 protocols:
14+
#
15+
# ```
16+
# ssl_context = OpenSSL::SSL::Context::Client.new
17+
# ssl_context.options = LibSSL::Options::NO_SSLV2 | LibSSL::Options::NO_SSLV3
18+
# ```
19+
def initialize(method : LibSSL::SSLMethod = LibSSL.sslv23_method)
20+
super(method)
21+
22+
self.verify_mode = OpenSSL::SSL::VerifyMode::PEER
2123
end
2224
end
2325

24-
# Generates a new SSL context with sane defaults for a server connection.
25-
#
26-
# By default it defaults to the `SSLv23_method` which actually means that
27-
# OpenSSL will negotiate the TLS or SSL protocol to use with the remote
28-
# endpoint.
29-
#
30-
# Don't change the method unless you must restrict a specific protocol to be
31-
# used (eg: TLSv1.2) and nothing else. You should specify options to disable
32-
# specific protocols, yet allow to negotiate from various other ones. For
33-
# example the following snippet will enable the TLSv1, TLSv1.1 and TLSv1.2
34-
# protocols but disable the deprecated SSLv2 and SSLv3 protocols:
35-
#
36-
# ```
37-
# ssl_context = OpenSSL::SSL::Context.new_for_server
38-
# ssl_context.options = LibSSL::Options::NO_SSLV2 | LibSSL::Options::NO_SSLV3
39-
# ```
40-
def self.new_for_server(method : LibSSL::SSLMethod = LibSSL.sslv23_method)
41-
new(method)
26+
class Server < Context
27+
# Generates a new SSL context with sane defaults for a server connection.
28+
#
29+
# By default it defaults to the `SSLv23_method` which actually means that
30+
# OpenSSL will negotiate the TLS or SSL protocol to use with the remote
31+
# endpoint.
32+
#
33+
# Don't change the method unless you must restrict a specific protocol to be
34+
# used (eg: TLSv1.2) and nothing else. You should specify options to disable
35+
# specific protocols, yet allow to negotiate from various other ones. For
36+
# example the following snippet will enable the TLSv1, TLSv1.1 and TLSv1.2
37+
# protocols but disable the deprecated SSLv2 and SSLv3 protocols:
38+
#
39+
# ```
40+
# ssl_context = OpenSSL::SSL::Context::Server.new
41+
# ssl_context.options = LibSSL::Options::NO_SSLV2 | LibSSL::Options::NO_SSLV3
42+
# ```
43+
def initialize(method : LibSSL::SSLMethod = LibSSL.sslv23_method)
44+
super(method)
45+
end
4246
end
4347

44-
private def initialize(method : LibSSL::SSLMethod = LibSSL.sslv23_method)
48+
protected def initialize(method : LibSSL::SSLMethod = LibSSL.sslv23_method)
4549
@handle = LibSSL.ssl_ctx_new(method)
4650
raise OpenSSL::Error.new("SSL_CTX_new") if @handle.null?
4751
LibSSL.ssl_ctx_set_default_verify_paths(@handle)

0 commit comments

Comments
 (0)