Skip to content

Commit

Permalink
Modified hotfix for something funny with sockets/sessions, updated li…
Browse files Browse the repository at this point in the history
…cense, implements PR#35

this works

cleanup

possible readall() fix

irb/tempfix plus some other functionality

see, e.g., osstech-jp/openldap@6ad808d

typo in license

removed commented code

implements PR #35
  • Loading branch information
IainNZ authored and sbromberger committed Feb 18, 2015
1 parent 0476e1f commit 9ee72bc
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 38 deletions.
4 changes: 2 additions & 2 deletions LICENSE.md
@@ -1,4 +1,4 @@
Readline.jl is licensed under the MIT License:
GnuTLS.jl is licensed under the MIT License:

> Copyright (c) 2013: Massachusetts Institute of Technology
> Copyright (c) 2013: Keno Fischer and other contributors.
Expand All @@ -20,4 +20,4 @@ Readline.jl is licensed under the MIT License:
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
98 changes: 62 additions & 36 deletions src/GnuTLS.jl
Expand Up @@ -8,16 +8,33 @@ include("../deps/deps.jl")

import Base: isopen, write, read, readall, readavailable, close, show, nb_available, eof


const GNUTLS_MINSECURE_VER = @compat Dict(
v"2.12" => 23,
v"3.1" => 28,
v"3.2" => 20,
v"3.3" => 10
)

const WRITE_RETURN_TYPE = VERSION >= v"0.4-" ? UInt64 : Int64
const gnutls_version = convert(VersionNumber,bytestring(ccall((:gnutls_check_version,gnutls),Ptr{Uint8},(Ptr{Uint8},),C_NULL)))

function versionisdeprecated(v::VersionNumber)
majmin = convert(VersionNumber,"$(v.major).$(v.minor)")
patch = v.patch
if haskey(GNUTLS_MINSECURE_VER, majmin)
return GNUTLS_MINSECURE_VER[majmin] > patch
else
return true
end
end

macro gnutls_since(v,f)
if isexpr(v,:macrocall) && v.args[1] == symbol("@v_str")
v = convert(VersionNumber,v.args[2])
end
if gnutls_version < v
msg = """This function is only supported in GnuTLS versions > $v.
To force GnuTLS.jl to build a more recent version, you may set
msg = """This function is only supported in GnuTLS versions > $v.
To force GnuTLS.jl to build a more recent version, you may set
ENV[\"GNUTLS_VERSION\"] and run Pkg.fixup()"""
body = quote
error($msg)
Expand Down Expand Up @@ -51,16 +68,18 @@ gnutls_error(err::Int32) = err < 0 ? throw(GnuTLSException(err)) : nothing
# Chrome does not Handle EOF properly, but instead just shuts down the transport. This function
# is a heuristic to determine whether that's what we're dealing with. Using this functions
# to ignore errors in HTTPS is allowed by RFC2818.
function is_premature_eof(err::GnuTLSException)
function is_premature_eof(code::Integer)
if gnutls_version < v"3.0"
# GNUTLS_E_UNEXPECTED_PACKAGE_LENGTH
return err.code == -9
return code == -9
else
# GNUTLS_E_PREMATURE_TERMINATION
return err.code == -110
return code == -110
end
end

is_premature_eof(err::GnuTLSException) = is_premature_eof(err.code)

# GnuTLS Session support

const GNUTLS_SERVER = 1
Expand All @@ -71,7 +90,7 @@ const GNUTLS_NO_EXTENSIONS = 1<<4

type Session <: IO
handle::Ptr{Void}
open::Bool
open::Bool
# For rooting purposes
read::IO
write::IO
Expand All @@ -89,16 +108,11 @@ const GNUTLS_SHUT_WR = 1


free_session(s::Session) = ccall((:gnutls_deinit,gnutls),Void,(Ptr{Void},),s.handle)
isopen(s::Session) = (isopen(s.read) || isopen(s.write))

isopen(s::Session) = (s.open && (isopen(s.read) || isopen(s.write)))
function close(s::Session)
ret::Int32 = 0
try # The remote might very well simply shut the stream rather than acknowledge the closure
ret = ccall((:gnutls_bye,gnutls), Int32, (Ptr{Void},Int32), s.handle, GNUTLS_SHUT_RDWR)
catch e
if !isa(e,EOFError)
rethrow()
end
ret = ccall((:gnutls_bye,gnutls), Int32, (Ptr{Void},Int32), s.handle, GNUTLS_SHUT_WR)
end
gnutls_error(ret)
s.open=false
Expand Down Expand Up @@ -144,7 +158,7 @@ type CertificateStore
handle::Ptr{Void}
# for rooting purposes
dh_parameters::DHParameters
function CertificateStore()
function CertificateStore()
x = Array(Ptr{Void},1)
gnutls_error(ccall((:gnutls_certificate_allocate_credentials,gnutls),Int32,(Ptr{Ptr{Void}},),x))
ret = new(x[1])
Expand All @@ -159,7 +173,7 @@ function set_dh_parameters(c::CertificateStore,dh::DHParameters)
end

free_certificate_store(x::CertificateStore) = ccall((:gnutls_certificate_free_credentials,gnutls),Void,(Ptr{Void},),x.handle)
@gnutls_since v"3.0" function set_system_trust!(c::CertificateStore)
@gnutls_since v"3.0" function set_system_trust!(c::CertificateStore)
ret = ccall((:gnutls_certificate_set_x509_system_trust,gnutls),Int32,(Ptr{Void},),c.handle)
if ret == -1250
return false
Expand Down Expand Up @@ -280,7 +294,7 @@ function poll_readable{S<:IO}(io::S,ms::Uint32)
wait(c)::Int32
end

function read_ptr{S<:IO}(io::S,ptr::Ptr{Uint8},size::Csize_t)
function read_ptr{S<:IO}(io::S,ptr::Ptr{Uint8},size::Csize_t)
Base.wait_readnb(io,1)
n = min(nb_available(io.buffer),size)
read!(io,pointer_to_array(ptr,int(n)))
Expand All @@ -292,20 +306,20 @@ function associate_stream{S<:IO,T<:IO}(s::Session, read::S, write::T=read)
s.write = write
if write == read
ccall((:gnutls_transport_set_ptr,gnutls),Void,(Ptr{Void},Any),s.handle,read)
else
else
ccall((:gnutls_transport_set_ptr2,gnutls),Void,(Ptr{Void},Any,Any),s.handle,read,write)
end
@gnutls_since v"3.0" ccall((:gnutls_transport_set_pull_timeout_function,gnutls),Void,(Ptr{Void},Ptr{Void}),s.handle,cfunction(poll_readable,Int32,(S,Uint32)))
ccall((:gnutls_transport_set_pull_function,gnutls),Void,(Ptr{Void},Ptr{Void}),s.handle,cfunction(read_ptr,Cssize_t,(S,Ptr{Uint8},Csize_t)))
ccall((:gnutls_transport_set_push_function,gnutls),Void,(Ptr{Void},Ptr{Void}),s.handle,cfunction(Base.write,Int64,(T,Ptr{Uint8},Csize_t)))
ccall((:gnutls_transport_set_push_function,gnutls),Void,(Ptr{Void},Ptr{Void}),s.handle,cfunction(Base.write,WRITE_RETURN_TYPE,(T,Ptr{Uint8},Csize_t)))
end

handshake!(s::Session) = (gnutls_error(ccall((:gnutls_handshake,gnutls),Int32,(Ptr{Void},),s.handle));s.open = true; nothing)
function set_priority_string!(s::Session,priority::ASCIIString="NORMAL")
function set_priority_string!(s::Session,priority::ASCIIString="NORMAL")
x = Array(Ptr{Uint8},1)
old_ptr = convert(Ptr{Uint8},priority)
ret = ccall((:gnutls_priority_set_direct,gnutls),Int32,(Ptr{Void},Ptr{Uint8},Ptr{Ptr{Uint8}}),s.handle,old_ptr,x)
offset = x[1] - old_ptr
offset = x[1] - old_ptr
gnutls_error("At priority string offset $offset: ",ret)
end

Expand All @@ -332,7 +346,7 @@ function set_prompt_client_certificate!(s::Session,required::Bool = true)
ccall((:gnutls_certificate_server_set_request,gnutls),Void,(Ptr{Void},Int32),s.handle,required?GNUTLS_CERT_REQUIRE:GNUTLS_CERT_REQUEST)
end

function write(io::Session, data::Ptr{Uint8}, size::Integer)
function write(io::Session, data::Ptr{Uint8}, size::Integer)
total = 0
while total < length(data)
ret = ccall((:gnutls_record_send,gnutls), Int, (Ptr{Void},Ptr{Uint8},Csize_t), io.handle, data+total, size-total)
Expand All @@ -344,7 +358,7 @@ function write(io::Session, data::Ptr{Uint8}, size::Integer)
total
end

function write(io::Session, data::Array{Uint8,1})
function write(io::Session, data::Array{Uint8,1})
total = 0
while total < length(data)
ret = ccall((:gnutls_record_send,gnutls), Int, (Ptr{Void},Ptr{Uint8},Csize_t), io.handle, pointer(data,total+1), length(data)-total)
Expand All @@ -370,29 +384,27 @@ function read(io::Session, data::Array{Uint8,1})
data
end

checkpending(io::Session) = convert(Bool, ccall((:gnutls_record_check_pending, gnutls), Int, (Ptr{Void},), io.handle))
recordmaxsize(io::Session) = ccall((:gnutls_record_get_max_size, gnutls), Int, (Ptr{Void},), io.handle)
recordcheckcorked(io::Session) = ccall((:gnutls_record_check_corked, gnutls), Int, (Ptr{Void},), io.handle)

function readtobuf(io::Session,buf::IOBuffer,nb)
Base.ensureroom(buf,int(nb))
ret = ccall((:gnutls_record_recv,gnutls), Int, (Ptr{Void},Ptr{Uint8},Csize_t), io.handle, pointer(buf.data,buf.size+1), nb)
if ret < 0
iseof = is_premature_eof(ret)
if ret < 0 && !(iseof)
gnutls_error(int32(ret))
elseif ret == 0
elseif ret == 0 || iseof
close(io)
return false
else
buf.size += ret
return true
end
buf.size += ret
return true
end

const TLS_CHUNK_SIZE = 4096
function readall(io::Session)
buf = IOBuffer(Array(Uint8,TLS_CHUNK_SIZE),true,true,true,true,typemax(Int))
buf.size = 0
while readtobuf(io,buf,TLS_CHUNK_SIZE); end
readall(buf)
end


nb_available(s::Session) = ccall((:gnutls_record_check_pending,gnutls), Csize_t, (Ptr{Void},), s.handle)

eof(s::Session) = (nb_available(s) == 0 && eof(s.read))

function readavailable(io::Session)
Expand All @@ -411,6 +423,14 @@ function readavailable(io::Session)
takebuf_array(buf)
end

function readall(io::Session)
arr = UInt8[]
while isopen(io)
append!(arr, readavailable(io))
end
arr
end

function write{T}(s::Session, a::Array{T})
if isbits(T)
write(s,reinterpret(Uint8,a))
Expand All @@ -427,6 +447,12 @@ function logging_func(level::Int32,msg::Ptr{Uint8})
end

function init()
if versionisdeprecated(gnutls_version)
msg = """This version of the GnuTLS library ($gnutls_version) is deprecated
and contains known security vulnerabilities. Please upgrade to a
more recent version."""
warn(msg)
end
ccall((:gnutls_global_set_mem_functions,gnutls),Void,
(Ptr{Void},Ptr{Void},Ptr{Void},Ptr{Void},Ptr{Void}),
cglobal(:jl_gc_counted_malloc), # Malloc
Expand Down

0 comments on commit 9ee72bc

Please sign in to comment.