-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds AMQPS (TLS) connections support. The IANA assigned port number for AMQPS is 5671. It is available as the constant `AMQPClient.AMQPS_DEFAULT_PORT`. An example of making an AMQPS connection: ```julia conn = connection(; virtualhost="/", host = "amqps.example.com", port = AMQPFlient.AMQPS_DEFAULT_PORT auth_params = Dict{String,Any}("MECHANISM"=>"AMQPLAIN", "LOGIN"=>"guest", "PASSWORD"=>"guest"), amqps = amqps_configure() ) ``` The `amqps_configure` method can be provided additional parameters for TLS connections: - cacerts: A CA certificate file (or it's contents) to use for certificate verification. - verify: Whether to verify server certificate. Default is false if cacerts is not provided and true if it is. - client_cert and client_key: The client certificate and corresponding private key to use. Default is nothing (no client certificate). Values can either be the file name or certificate/key contents. ```julia amqps_configure(; cacerts = nothing, verify = MbedTLS.MBEDTLS_SSL_VERIFY_NONE, client_cert = nothing, client_key = nothing ) ```
- Loading branch information
Showing
11 changed files
with
562 additions
and
283 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
function default_tls_debug(level, filename, number, msg) | ||
@debug(level, filename, number, msg) | ||
end | ||
|
||
function default_tls_rng() | ||
entropy = MbedTLS.Entropy() | ||
rng = MbedTLS.CtrDrbg() | ||
MbedTLS.seed!(rng, entropy) | ||
rng | ||
end | ||
|
||
""" | ||
amqps_configure(; | ||
cacerts = nothing, | ||
verify = MbedTLS.MBEDTLS_SSL_VERIFY_NONE, | ||
client_cert = nothing, | ||
client_key = nothing | ||
) | ||
Creates and returns a configuration for making AMQPS connections. | ||
- cacerts: A CA certificate file (or it's contents) to use for certificate verification. | ||
- verify: Whether to verify server certificate. Default is false if cacerts is not provided and true if it is. | ||
- client_cert and client_key: The client certificate and corresponding private key to use. Default is nothing (no client certificate). Values can either be the file name or certificate/key contents. | ||
""" | ||
function amqps_configure(; | ||
rng = default_tls_rng(), | ||
cacerts::Union{String,Nothing} = nothing, | ||
verify::Int64 = (cacerts === nothing) ? MbedTLS.MBEDTLS_SSL_VERIFY_NONE : MbedTLS.MBEDTLS_SSL_VERIFY_REQUIRED, | ||
client_cert::Union{String,Nothing} = nothing, | ||
client_key::Union{String,Nothing} = nothing, | ||
debug::Union{Function,Nothing} = nothing) | ||
|
||
conf = MbedTLS.SSLConfig() | ||
MbedTLS.config_defaults!(conf) | ||
MbedTLS.rng!(conf, rng) | ||
(debug === nothing) || MbedTLS.dbg!(conf, debug) | ||
|
||
if cacerts !== nothing | ||
if isfile(cacerts) | ||
# if it is a file name instead of certificate contents, read the contents | ||
cacerts = read(cacerts, String) | ||
end | ||
MbedTLS.ca_chain!(conf, MbedTLS.crt_parse(cacerts)) | ||
end | ||
MbedTLS.authmode!(conf, verify) | ||
|
||
if (client_cert !== nothing) && (client_key !== nothing) | ||
if isfile(client_cert) | ||
# if it is a file name instead of certificate contents, read the contents | ||
client_cert = read(client_cert, String) | ||
end | ||
if isfile(client_key) | ||
client_key = read(client_key, String) | ||
end | ||
key = MbedTLS.PKContext() | ||
MbedTLS.parse_key!(key, client_key) | ||
MbedTLS.own_cert!(conf, MbedTLS.crt_parse(client_cert), key) | ||
end | ||
|
||
conf | ||
end | ||
|
||
function setup_tls(sock::TCPSocket, hostname::String, ssl_options::MbedTLS.SSLConfig) | ||
@debug("setting up TLS") | ||
|
||
ctx = MbedTLS.SSLContext() | ||
MbedTLS.setup!(ctx, ssl_options) | ||
MbedTLS.set_bio!(ctx, sock) | ||
MbedTLS.hostname!(ctx, hostname) | ||
MbedTLS.handshake(ctx) | ||
@debug("TLS setup done") | ||
|
||
BufferedTLSSocket(ctx) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
const TLS_BUSY_READ_SECS = 1 | ||
const TLS_BUSY_READ_YIELD_SECS = 0.001 | ||
const TLS_READBUFF_SIZE = MbedTLS.MBEDTLS_SSL_MAX_CONTENT_LEN * 5 | ||
const TLS_MIN_WRITEBUFF_SIZE = MbedTLS.MBEDTLS_SSL_MAX_CONTENT_LEN | ||
const TCP_MAX_WRITEBUFF_SIZE = 1024*512 | ||
const TCP_MIN_WRITEBUFF_SIZE = 1024*64 | ||
|
||
struct BufferedTLSSocket <: IO | ||
in::IOBuffer # no read lock, single task reads socket and distributes messages to channels | ||
out::IOBuffer | ||
sock::MbedTLS.SSLContext | ||
readbuff::Vector{UInt8} | ||
out_lck::ReentrantLock # protect out::IOBuffer when there are multiple channels on the connection | ||
|
||
function BufferedTLSSocket(sock::MbedTLS.SSLContext; readbuff_size::Int=TLS_READBUFF_SIZE) | ||
new(PipeBuffer(), PipeBuffer(), sock, Vector{UInt8}(undef, readbuff_size), ReentrantLock()) | ||
end | ||
end | ||
|
||
isopen(bio::BufferedTLSSocket) = isopen(bio.sock) | ||
close(bio::BufferedTLSSocket) = close(bio.sock) | ||
|
||
function read(bio::BufferedTLSSocket, ::Type{UInt8}) | ||
fill_in(bio, 1) | ||
read(bio.in, UInt8) | ||
end | ||
|
||
function read(bio::BufferedTLSSocket, T::Union{Type{Int16},Type{UInt16},Type{Int32},Type{UInt32},Type{Int64},Type{UInt64},Type{Int128},Type{UInt128},Type{Float16},Type{Float32},Type{Float64}}) | ||
fill_in(bio, sizeof(T)) | ||
read(bio.in, T) | ||
end | ||
|
||
function read!(bio::BufferedTLSSocket, buff::Vector{UInt8}) | ||
fill_in(bio, length(buff)) | ||
read!(bio.in, buff) | ||
end | ||
|
||
function peek(bio::BufferedTLSSocket, T::Union{Type{Int16},Type{UInt16},Type{Int32},Type{UInt32},Type{Int64},Type{UInt64},Type{Int128},Type{UInt128},Type{Float16},Type{Float32},Type{Float64}}) | ||
fill_in(bio, sizeof(T)) | ||
peek(bio.in, T) | ||
end | ||
|
||
function fill_in(bio::BufferedTLSSocket, atleast::Int) | ||
avail = bytesavailable(bio.in) | ||
if atleast > avail | ||
while (atleast > avail) && isopen(bio.sock) | ||
bytes_read = isreadable(bio.sock) ? readbytes!(bio.sock, bio.readbuff; all=false) : 0 | ||
if bytes_read > 0 | ||
avail += Base.write_sub(bio.in, bio.readbuff, 1, bytes_read) | ||
else | ||
MbedTLS.wait_for_decrypted_data(bio.sock) | ||
end | ||
end | ||
end | ||
end | ||
|
||
function write(bio::BufferedTLSSocket, data::UInt8) | ||
lock(bio.out_lck) do | ||
write(bio.out, data) | ||
end | ||
end | ||
function write(bio::BufferedTLSSocket, data::Union{Int16,UInt16,Int32,UInt32,Int64,UInt64,Int128,UInt128,Float16,Float32,Float64}) | ||
lock(bio.out_lck) do | ||
write(bio.out, data) | ||
end | ||
end | ||
function write(bio::BufferedTLSSocket, data::Array) | ||
lock(bio.out_lck) do | ||
write(bio.out, data) | ||
end | ||
end | ||
function flush(bio::BufferedTLSSocket) | ||
lock(bio.out_lck) do | ||
write(bio.sock, take!(bio.out)) | ||
end | ||
nothing | ||
end |
Oops, something went wrong.