mirror of
https://gitea.invidious.io/iv-org/lsquic.cr
synced 2024-08-15 00:43:31 +00:00
Add patch for BoringSSL
This commit is contained in:
parent
6e4b028f45
commit
fcf16e715a
3 changed files with 190 additions and 2 deletions
|
@ -1,5 +1,4 @@
|
|||
require "./lsquic/*"
|
||||
# require "http/headers"
|
||||
require "http"
|
||||
require "socket"
|
||||
|
||||
|
@ -17,6 +16,8 @@ HEADERS = HTTP::Headers{
|
|||
# "content-length" => "0",
|
||||
}
|
||||
|
||||
pp HTTP::Client.get("https://www.youtube.com#{PATH}").status_code
|
||||
|
||||
# logger_if = LibLsquic::LoggerIf.new
|
||||
# logger_if.log_buf = ->(logger_ctx : Void*, msg_buf : LibC::Char*, msg_size : LibC::SizeT) { puts String.new(msg_buf); 0 }
|
||||
# LibLsquic.logger_init(pointerof(logger_if), nil, LibLsquic::LoggerTimestampStyle::LltsHhmmssms)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@[Link(ldflags: "#{__DIR__}/ext/liblsquic.a #{__DIR__}/ext/libssl.a #{__DIR__}/ext/libcrypto.a -lz")]
|
||||
@[Link(ldflags: "#{__DIR__}/ext/liblsquic.a")]
|
||||
lib LibLsquic
|
||||
MAX_CID_LEN = 20
|
||||
QQUIC_CID_LEN = 8
|
||||
|
@ -375,3 +375,5 @@ lib LibLsquic
|
|||
end
|
||||
$ver2str : LibC::Char*[6]
|
||||
end
|
||||
|
||||
require "./patch"
|
||||
|
|
185
src/lsquic/patch.cr
Normal file
185
src/lsquic/patch.cr
Normal file
|
@ -0,0 +1,185 @@
|
|||
require "openssl/lib_ssl"
|
||||
require "openssl/lib_crypto"
|
||||
require "openssl/bio"
|
||||
|
||||
@[Link(ldflags: "#{__DIR__}/ext/liblsquic.a #{__DIR__}/ext/libcrypto.a")]
|
||||
lib LibCrypto
|
||||
fun evp_ripemd160 = EVP_sha1 : EVP_MD
|
||||
fun sk_free = sk_free(st : Void*)
|
||||
fun sk_num = sk_num(x0 : Void*) : Int
|
||||
fun sk_pop_free = sk_pop_free(st : Void*, callback : (Void*) ->)
|
||||
fun sk_value = sk_value(x0 : Void*, x1 : Int) : Void*
|
||||
end
|
||||
|
||||
@[Link(ldflags: "#{__DIR__}/ext/libssl.a")]
|
||||
lib LibSSL
|
||||
fun ssl_set_tlsext_host_name = SSL_set_tlsext_host_name(handle : SSL, name : Char*) : Long
|
||||
fun ssl_ctx_set_tmp_ecdh = SSL_CTX_set_tmp_ecdh(ctx : SSLContext, parg : Void*) : ULong
|
||||
fun ssl_ctx_get_mode = SSL_CTX_get_mode(ctx : SSLContext) : ULong
|
||||
fun ssl_ctx_set_mode = SSL_CTX_set_mode(ctx : SSLContext, mode : ULong) : ULong
|
||||
fun ssl_ctx_clear_mode = SSL_CTX_clear_mode(ctx : SSLContext, mode : ULong) : ULong
|
||||
end
|
||||
|
||||
require "openssl/ssl/context"
|
||||
|
||||
abstract class OpenSSL::SSL::Context
|
||||
def set_tmp_ecdh_key(curve = LibCrypto::NID_X9_62_prime256v1)
|
||||
key = LibCrypto.ec_key_new_by_curve_name(curve)
|
||||
raise OpenSSL::Error.new("ec_key_new_by_curve_name") if key.null?
|
||||
LibSSL.ssl_ctx_set_tmp_ecdh(@handle, key)
|
||||
LibCrypto.ec_key_free(key)
|
||||
end
|
||||
|
||||
# Returns the current modes set on the TLS context.
|
||||
def modes
|
||||
OpenSSL::SSL::Modes.new LibSSL.ssl_ctx_get_mode(@handle)
|
||||
end
|
||||
|
||||
# Adds modes to the TLS context.
|
||||
def add_modes(mode : OpenSSL::SSL::Modes)
|
||||
OpenSSL::SSL::Modes.new LibSSL.ssl_ctx_set_mode(@handle, mode)
|
||||
end
|
||||
|
||||
# Removes modes from the TLS context.
|
||||
def remove_modes(mode : OpenSSL::SSL::Modes)
|
||||
OpenSSL::SSL::Modes.new LibSSL.ssl_ctx_clear_mode(@handle, mode)
|
||||
end
|
||||
end
|
||||
|
||||
struct OpenSSL::BIO
|
||||
CRYSTAL_BIO_BORING = begin
|
||||
bwrite = LibCrypto::BioMethodWriteOld.new do |bio, data, len|
|
||||
io = Box(IO).unbox(BIO.get_data(bio))
|
||||
io.write Slice.new(data, len)
|
||||
len
|
||||
end
|
||||
|
||||
bwrite_ex = LibCrypto::BioMethodWrite.new do |bio, data, len, writep|
|
||||
count = len > Int32::MAX ? Int32::MAX : len.to_i
|
||||
io = Box(IO).unbox(BIO.get_data(bio))
|
||||
io.write Slice.new(data, count)
|
||||
writep.value = LibC::SizeT.new(count)
|
||||
1
|
||||
end
|
||||
|
||||
bread = LibCrypto::BioMethodReadOld.new do |bio, buffer, len|
|
||||
io = Box(IO).unbox(BIO.get_data(bio))
|
||||
io.flush
|
||||
io.read(Slice.new(buffer, len)).to_i
|
||||
end
|
||||
|
||||
bread_ex = LibCrypto::BioMethodWrite.new do |bio, buffer, len, readp|
|
||||
count = len > Int32::MAX ? Int32::MAX : len.to_i
|
||||
io = Box(IO).unbox(BIO.get_data(bio))
|
||||
io.flush
|
||||
ret = io.read Slice.new(buffer, count)
|
||||
readp.value = LibC::SizeT.new(ret)
|
||||
1
|
||||
end
|
||||
|
||||
ctrl = LibCrypto::BioMethodCtrl.new do |bio, cmd, num, ptr|
|
||||
io = Box(IO).unbox(BIO.get_data(bio))
|
||||
|
||||
val = case cmd
|
||||
when LibCrypto::CTRL_FLUSH
|
||||
io.flush
|
||||
1
|
||||
when LibCrypto::CTRL_PUSH, LibCrypto::CTRL_POP
|
||||
0
|
||||
else
|
||||
STDERR.puts "WARNING: Unsupported BIO ctrl call (#{cmd})"
|
||||
0
|
||||
end
|
||||
LibCrypto::Long.new(val)
|
||||
end
|
||||
|
||||
create = LibCrypto::BioMethodCreate.new do |bio|
|
||||
{% if compare_versions(LibCrypto::OPENSSL_VERSION, "1.1.0") >= 0 %}
|
||||
LibCrypto.BIO_set_shutdown(bio, 1)
|
||||
LibCrypto.BIO_set_init(bio, 1)
|
||||
# bio.value.num = -1
|
||||
{% else %}
|
||||
bio.value.shutdown = 1
|
||||
bio.value.init = 1
|
||||
bio.value.num = -1
|
||||
{% end %}
|
||||
1
|
||||
end
|
||||
|
||||
destroy = LibCrypto::BioMethodDestroy.new do |bio|
|
||||
BIO.set_data(bio, Pointer(Void).null)
|
||||
1
|
||||
end
|
||||
|
||||
{% if compare_versions(LibCrypto::OPENSSL_VERSION, "1.1.0") >= 0 %}
|
||||
biom = LibCrypto.BIO_meth_new(Int32::MAX, "Crystal BIO")
|
||||
|
||||
LibCrypto.BIO_meth_set_write(biom, bwrite)
|
||||
LibCrypto.BIO_meth_set_read(biom, bread)
|
||||
LibCrypto.BIO_meth_set_ctrl(biom, ctrl)
|
||||
LibCrypto.BIO_meth_set_create(biom, create)
|
||||
LibCrypto.BIO_meth_set_destroy(biom, destroy)
|
||||
biom
|
||||
{% else %}
|
||||
biom = Pointer(LibCrypto::BioMethod).malloc(1)
|
||||
biom.value.type_id = Int32::MAX
|
||||
biom.value.name = "Crystal BIO"
|
||||
biom.value.bwrite = bwrite
|
||||
biom.value.bread = bread
|
||||
biom.value.ctrl = ctrl
|
||||
biom.value.create = create
|
||||
biom.value.destroy = destroy
|
||||
biom
|
||||
{% end %}
|
||||
end
|
||||
|
||||
def initialize(@io : IO)
|
||||
@bio = LibCrypto.BIO_new(CRYSTAL_BIO_BORING)
|
||||
|
||||
# We need to store a reference to the box because it's
|
||||
# stored in `@bio.value.ptr`, but that lives in C-land,
|
||||
# not in Crystal-land.
|
||||
@boxed_io = Box(IO).box(io)
|
||||
|
||||
BIO.set_data(@bio, @boxed_io)
|
||||
end
|
||||
end
|
||||
|
||||
require "openssl/ssl/socket"
|
||||
|
||||
abstract class OpenSSL::SSL::Socket < IO
|
||||
class Client < Socket
|
||||
def initialize(io, context : Context::Client = Context::Client.new, sync_close : Bool = false, hostname : String? = nil)
|
||||
super(io, context, sync_close)
|
||||
begin
|
||||
if hostname
|
||||
LibSSL.ssl_set_tlsext_host_name(@ssl, hostname)
|
||||
|
||||
{% if compare_versions(LibSSL::OPENSSL_VERSION, "1.0.2") >= 0 %}
|
||||
param = LibSSL.ssl_get0_param(@ssl)
|
||||
|
||||
if ::Socket.ip?(hostname)
|
||||
unless LibCrypto.x509_verify_param_set1_ip_asc(param, hostname) == 1
|
||||
raise OpenSSL::Error.new("X509_VERIFY_PARAM_set1_ip_asc")
|
||||
end
|
||||
else
|
||||
unless LibCrypto.x509_verify_param_set1_host(param, hostname, hostname.bytesize) == 1
|
||||
raise OpenSSL::Error.new("X509_VERIFY_PARAM_set1_host")
|
||||
end
|
||||
end
|
||||
{% else %}
|
||||
context.set_cert_verify_callback(hostname)
|
||||
{% end %}
|
||||
end
|
||||
|
||||
ret = LibSSL.ssl_connect(@ssl)
|
||||
unless ret == 1
|
||||
raise OpenSSL::SSL::Error.new(@ssl, ret, "SSL_connect")
|
||||
end
|
||||
rescue ex
|
||||
LibSSL.ssl_free(@ssl) # GC never calls finalize, avoid mem leak
|
||||
raise ex
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue