123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675open!Base[%%import"config.h"]moduleVoidp(T:sigvalname:stringend):sigtypet[@@derivingsexp_of]valt:tCtypes.typvalt_opt:toptionCtypes.typend=structtypet=unitCtypes.ptrlett=Ctypes.(ptrvoid)lett_opt=Ctypes.(ptr_optvoid)letsexp_of_tt=[%sexp(T.name:string),(Ctypes.raw_address_of_ptrt:Base.Nativeint.Hex.t)];;endmoduleBignum=Voidp(structletname="Bignum"end)moduleSsl=Voidp(structletname="Ssl"end)moduleRsa=Voidp(structletname="Rsa"end)moduleDh=Voidp(structletname="Dh"end)moduleProgress_callback=(valForeign.dynamic_funptrCtypes.(int@->int@->ptrvoid@->returningvoid))moduleTmp_dh_callback=(valForeign.dynamic_funptrCtypes.(Ssl.t@->bool@->int@->returningDh.t))moduleTmp_rsa_callback=(valForeign.dynamic_funptrCtypes.(Ssl.t@->bool@->int@->returningRsa.t))moduleTypes(F:Cstubs.Types.TYPE)=structmoduleSsl_op=struct(*$
open Core;;
List.iter
[ "SSL_OP_NO_SSLv2"
; "SSL_OP_NO_SSLv3"
; "SSL_OP_NO_TLSv1"
; "SSL_OP_NO_TLSv1_1"
; "SSL_OP_NO_TLSv1_2"
; "SSL_OP_NO_TLSv1_3"
; "SSL_OP_SINGLE_DH_USE"
; "SSL_OP_SINGLE_ECDH_USE"
]
~f:(fun c_sym ->
let ml_sym = String.chop_prefix_exn c_sym ~prefix:"SSL_OP_" |> String.lowercase in
let fallback = "Unsigned.ULong.zero" in
print_endline
[%string
{|
[%%if defined JSC_%{c_sym}]
let %{ml_sym} = F.constant "%{c_sym}" F.ulong
[%%else]
let %{ml_sym} = %{fallback}
[%%endif] |}])
*)[%%ifdefinedJSC_SSL_OP_NO_SSLv2]letno_sslv2=F.constant"SSL_OP_NO_SSLv2"F.ulong[%%else]letno_sslv2=Unsigned.ULong.zero[%%endif][%%ifdefinedJSC_SSL_OP_NO_SSLv3]letno_sslv3=F.constant"SSL_OP_NO_SSLv3"F.ulong[%%else]letno_sslv3=Unsigned.ULong.zero[%%endif][%%ifdefinedJSC_SSL_OP_NO_TLSv1]letno_tlsv1=F.constant"SSL_OP_NO_TLSv1"F.ulong[%%else]letno_tlsv1=Unsigned.ULong.zero[%%endif][%%ifdefinedJSC_SSL_OP_NO_TLSv1_1]letno_tlsv1_1=F.constant"SSL_OP_NO_TLSv1_1"F.ulong[%%else]letno_tlsv1_1=Unsigned.ULong.zero[%%endif][%%ifdefinedJSC_SSL_OP_NO_TLSv1_2]letno_tlsv1_2=F.constant"SSL_OP_NO_TLSv1_2"F.ulong[%%else]letno_tlsv1_2=Unsigned.ULong.zero[%%endif][%%ifdefinedJSC_SSL_OP_NO_TLSv1_3]letno_tlsv1_3=F.constant"SSL_OP_NO_TLSv1_3"F.ulong[%%else]letno_tlsv1_3=Unsigned.ULong.zero[%%endif][%%ifdefinedJSC_SSL_OP_SINGLE_DH_USE]letsingle_dh_use=F.constant"SSL_OP_SINGLE_DH_USE"F.ulong[%%else]letsingle_dh_use=Unsigned.ULong.zero[%%endif][%%ifdefinedJSC_SSL_OP_SINGLE_ECDH_USE]letsingle_ecdh_use=F.constant"SSL_OP_SINGLE_ECDH_USE"F.ulong[%%else]letsingle_ecdh_use=Unsigned.ULong.zero[%%endif](*$*)endmoduleVerify_mode=structletverify_none=F.constant"SSL_VERIFY_NONE"F.intletverify_peer=F.constant"SSL_VERIFY_PEER"F.intletverify_fail_if_no_peer_cert=F.constant"SSL_VERIFY_FAIL_IF_NO_PEER_CERT"F.intletverify_client_once=F.constant"SSL_VERIFY_CLIENT_ONCE"F.intendmoduleVerify_result=struct(* Other codes should be obtained with X509.verify_cert_error_string *)letok=F.constant"X509_V_OK"F.longendmoduleSsl_error=structletnone=F.constant"SSL_ERROR_NONE"F.intletzero_return=F.constant"SSL_ERROR_ZERO_RETURN"F.intletwant_read=F.constant"SSL_ERROR_WANT_READ"F.intletwant_write=F.constant"SSL_ERROR_WANT_WRITE"F.intletwant_connect=F.constant"SSL_ERROR_WANT_CONNECT"F.intletwant_accept=F.constant"SSL_ERROR_WANT_ACCEPT"F.intletwant_x509_lookup=F.constant"SSL_ERROR_WANT_X509_LOOKUP"F.intletsyscall=F.constant"SSL_ERROR_SYSCALL"F.intletssl=F.constant"SSL_ERROR_SSL"F.intendmoduleX509_filetype=structletpem=F.constant"X509_FILETYPE_PEM"F.intletasn1=F.constant"X509_FILETYPE_ASN1"F.intendmoduleEvp=structletmax_md_size=F.constant"EVP_MAX_MD_SIZE"F.intendendmoduleBindings(F:Cstubs.FOREIGN)=structletforeign=F.foreignmoduleCtypes=structincludeCtypeslet(@->)=F.(@->)letreturning=F.returningletforeign=F.foreignletforeign_value=F.foreign_valueend(* Some systems with older OpenSSL don't support TLS 1.1 and 1.2.
https://github.com/janestreet/async_ssl/issues/3
This was originally solved by using [Ctypes_foreign.Foreign.foreign ~stub:true].
We now detect available symbols at compile time.
Bindings are uniformly using stubs (no libffi dependency).
Note: using [Ctypes_foreign.Foreign.foreign ~stub:true] was failing (segfault)
with 32bit build on 64bit host.
*)moduleSsl_method=structincludeVoidp(structletname="Ssl_method"end)letdummyname()=failwith(Printf.sprintf"Ssl_method %s not implemented"name)letimplementedname=foreignnameCtypes.(void@->returningt)lethelpernamef=fname(*$
open Core;;
List.iter
[ "SSLv23_method"
; "TLS_method"
; "SSLv3_method"
; "TLSv1_method"
; "TLSv1_1_method"
; "TLSv1_2_method"
; "TLSv1_3_method"
]
~f:(fun c_sym ->
let ml_sym = String.chop_suffix_exn c_sym ~suffix:"_method" |> String.lowercase in
let fallback =
if String.equal c_sym "TLS_method"
then "sslv23"
else [%string {|helper "%{c_sym}" dummy|}]
in
print_endline
[%string
{|
[%%if defined JSC_%{c_sym}]
let %{ml_sym} = helper "%{c_sym}" implemented
[%%else]
let %{ml_sym} = %{fallback}
[%%endif] |}])
*)[%%ifdefinedJSC_SSLv23_method]letsslv23=helper"SSLv23_method"implemented[%%else]letsslv23=helper"SSLv23_method"dummy[%%endif][%%ifdefinedJSC_TLS_method]lettls=helper"TLS_method"implemented[%%else]lettls=sslv23[%%endif][%%ifdefinedJSC_SSLv3_method]letsslv3=helper"SSLv3_method"implemented[%%else]letsslv3=helper"SSLv3_method"dummy[%%endif][%%ifdefinedJSC_TLSv1_method]lettlsv1=helper"TLSv1_method"implemented[%%else]lettlsv1=helper"TLSv1_method"dummy[%%endif][%%ifdefinedJSC_TLSv1_1_method]lettlsv1_1=helper"TLSv1_1_method"implemented[%%else]lettlsv1_1=helper"TLSv1_1_method"dummy[%%endif][%%ifdefinedJSC_TLSv1_2_method]lettlsv1_2=helper"TLSv1_2_method"implemented[%%else]lettlsv1_2=helper"TLSv1_2_method"dummy[%%endif][%%ifdefinedJSC_TLSv1_3_method]lettlsv1_3=helper"TLSv1_3_method"implemented[%%else]lettlsv1_3=helper"TLSv1_3_method"dummy[%%endif](*$*)(* SSLv2 isn't secure, so we don't use it. If you really really really need it, use
SSLv23 which will at least try to upgrade the security whenever possible.
let sslv2_method = foreign "SSLv2_method" ssl_method_t
*)endleterr_get_error=foreign"ERR_get_error"Ctypes.(void@->returningulong)leterr_error_string_n=foreign"ERR_error_string_n"Ctypes.(ulong@->ptrchar@->int@->returningvoid);;letadd_all_digests=foreign"OpenSSL_add_all_digests"Ctypes.(void@->returningvoid)letadd_all_ciphers=foreign"OpenSSL_add_all_ciphers"Ctypes.(void@->returningvoid)letadd_ssl_algorithms=foreign"OpenSSL_add_ssl_algorithms"Ctypes.(void@->returningvoid);;letopenssl_config=foreign"OPENSSL_config"Ctypes.(string_opt@->returningvoid)letinit=foreign"SSL_library_init"Ctypes.(void@->returningulong)letssl_load_error_strings=foreign"SSL_load_error_strings"Ctypes.(void@->returningvoid);;leterr_load_crypto_strings=foreign"ERR_load_crypto_strings"Ctypes.(void@->returningvoid);;moduleEngine=structletload_builtin_engines=foreign"ENGINE_load_builtin_engines"Ctypes.(void@->returningvoid);;letregister_all_complete=foreign"ENGINE_register_all_complete"Ctypes.(void@->returningvoid);;endmoduleSsl_ctx=structincludeVoidp(structletname="Ssl_ctx"end)(* free with SSL_CTX_free() (source: manpage of SSL_CTX_free(3)) *)letnew_=foreign"SSL_CTX_new"Ctypes.(Ssl_method.t@->returningt_opt)letfree=foreign"SSL_CTX_free"Ctypes.(t@->returningvoid)letoverride_default_insecure__set_security_level=foreign"SSL_CTX_set_security_level"Ctypes.(t@->int@->returningvoid);;letload_verify_locations=foreign"SSL_CTX_load_verify_locations"Ctypes.(t@->string_opt@->string_opt@->returningint);;letset_default_verify_paths=foreign"SSL_CTX_set_default_verify_paths"Ctypes.(t@->returningint);;letset_session_id_context=foreign"SSL_CTX_set_session_id_context"Ctypes.(t@->ptrchar@->uint@->returningint);;letset_cipher_list=foreign"SSL_CTX_set_cipher_list"Ctypes.(t@->string@->returningint);;letset_options=foreign"SSL_CTX_set_options"Ctypes.(t@->ulong@->returningulong);;letuse_certificate_chain_file=foreign"SSL_CTX_use_certificate_chain_file"Ctypes.(t@->string@->returningint);;letuse_certificate_file=foreign"SSL_CTX_use_certificate_file"Ctypes.(t@->string@->int@->returningint);;letuse_private_key_file=foreign"SSL_CTX_use_PrivateKey_file"Ctypes.(t@->string@->int@->returningint);;letset_alpn_protos=foreign"SSL_CTX_set_alpn_protos"Ctypes.(t@->ptrchar@->uint@->returningint);;letset_alpn_callback=foreign"async_ssl__set_alpn_callback"Ctypes.(t@->ptrchar@->uint@->returning(ptrvoid));;letfree_alpn_callback=foreign"async_ssl__free_alpn_callback"Ctypes.(ptrvoid@->returningvoid);;endmoduleBio=structincludeVoidp(structletname="Bio"end)(* for use in ctypes signatures *)(* Returns a [BIO *] that is later assigned to an [SSL] object by calling
SSL_set_bio(3). The [BIO *] is freed automatically when calling SSL_free().
(source: manpage of SSL_free(3)) *)letnew_=foreign"BIO_new"Ctypes.(ptrvoid@->returningt)lets_mem=foreign"BIO_s_mem"Ctypes.(void@->returning(ptrvoid))letread=foreign"BIO_read"Ctypes.(t@->ptrchar@->int@->returningint)letwrite=foreign"BIO_write"Ctypes.(t@->string@->int@->returningint)endmoduleASN1_object=structincludeVoidp(structletname="ASN1_object"end)letobj2nid=foreign"OBJ_obj2nid"Ctypes.(t@->returningint)(* returns pointer to statically-allocated string, do not free (source: obj_dat.[hc]
in openssl source) *)letnid2sn=foreign"OBJ_nid2sn"Ctypes.(int@->returningstring_opt)lettxt2nid=foreign"OBJ_txt2nid"Ctypes.(string@->returningint)endmoduleASN1_string=structincludeVoidp(structletname="ASN1_string"end)letlength=foreign"ASN1_STRING_length"Ctypes.(t@->returningint)(* returns internal pointer, do not free (source: manpage of ASN1_STRING_data(3)) *)letdata=foreign"ASN1_STRING_data"Ctypes.(t@->returningstring)endmoduleX509_name_entry=structincludeVoidp(structletname="X509_name_entry"end)(* returns pointer to field in [t], do not free (source: x509name.c in openssl
source) *)letget_object=foreign"X509_NAME_ENTRY_get_object"Ctypes.(t@->returningASN1_object.t);;(* returns pointer to field in [t], do not free (source: x509name.c in openssl
source) *)letget_data=foreign"X509_NAME_ENTRY_get_data"Ctypes.(t@->returningASN1_string.t);;endmoduleX509_name=structincludeVoidp(structletname="X509_name"end)letentry_count=foreign"X509_NAME_entry_count"Ctypes.(t@->returningint)(* returns internal pointer, do not free (source: manpage of
X509_NAME_get_entry(3)) *)letget_entry=foreign"X509_NAME_get_entry"Ctypes.(t@->int@->returningX509_name_entry.t);;endmoduleEVP=structincludeVoidp(structletname="EVP"end)letsha1=foreign"EVP_sha1"Ctypes.(void@->returningt)endmoduleX509=structincludeVoidp(structletname="X509"end)(* returns internal pointer, do not free (source: manpage of
X509_get_subject_name(3)) *)letget_subject_name=foreign"X509_get_subject_name"Ctypes.(t@->returningX509_name.t_opt);;letverify_cert_error_string=foreign"X509_verify_cert_error_string"Ctypes.(long@->returningstring_opt);;letfree=foreign"X509_free"Ctypes.(t@->returningvoid)letsubject_alt_names=foreign"async_ssl__subject_alt_names"Ctypes.(t@->returning(ptr_opt(ptr_optchar)));;letfree_subject_alt_names=foreign"async_ssl__free_subject_alt_names"Ctypes.(ptr(ptr_optchar)@->returningvoid);;letdigest=foreign"X509_digest"Ctypes.(t@->EVP.t@->ptrchar@->ptrint@->returningbool);;letcheck_host=foreign"X509_check_host"Ctypes.(t@->string@->int@->int@->ptr_optvoid@->returningint);;letcheck_ip=foreign"X509_check_ip_asc"Ctypes.(t@->string@->int@->returningint);;endmoduleSsl_session=structincludeVoidp(structletname="Ssl_session"end)(* free with SSL_SESSION_free() (source: manpage of SSL_SESSION_free(3)) *)letnew_=foreign"SSL_SESSION_new"Ctypes.(void@->returningt_opt)letfree=foreign"SSL_SESSION_free"Ctypes.(t@->returningvoid)endmoduleBignum=structincludeBignumletnew_=foreign"BN_new"Ctypes.(void@->returningt_opt)letfree=foreign"BN_free"Ctypes.(t@->returningvoid)letbin2bn=foreign"BN_bin2bn"Ctypes.(ptrchar@->int@->t@->returningt)lethex2bn=foreign"BN_hex2bn"Ctypes.(ptrt_opt@->string@->returningint)endmoduleProgress_callback=Progress_callbackmoduleDh=structincludeDhletnew_=foreign"DH_new"Ctypes.(void@->returningt_opt)letfree=foreign"DH_free"Ctypes.(t@->returningvoid)letgenerate_parameters=foreign"DH_generate_parameters"Ctypes.(int@->int@->Progress_callback.t_opt@->ptrvoid@->returningt_opt);;moduleStruct=structtypetlett:tCtypes.structureCtypes.typ=Ctypes.structure"DH"(*_ a bunch of fields we don't care about but we need for ctypes to not break *)let_pad=Ctypes.fieldt"pad"Ctypes.intlet_version=Ctypes.fieldt"version"Ctypes.int(*_ we actually need these two fields to be able to create [DH*] values *)letp=Ctypes.fieldt"p"Bignum.tletg=Ctypes.fieldt"g"Bignum.t(*_ lots more fields that we don't care about *)let()=Ctypes.sealtendendmoduleSsl=structincludeSsl(* free with SSL_free() (source: manpage of SSL_free(3)) *)letnew_=foreign"SSL_new"Ctypes.(Ssl_ctx.t@->returningt_opt)letfree=foreign"SSL_free"Ctypes.(t@->returningvoid)letset_method=foreign"SSL_set_ssl_method"Ctypes.(t@->Ssl_method.t@->returningint);;letget_error=foreign"SSL_get_error"Ctypes.(t@->int@->returningint)letset_connect_state=foreign"SSL_set_connect_state"Ctypes.(t@->returningvoid)letset_accept_state=foreign"SSL_set_accept_state"Ctypes.(t@->returningvoid)letconnect=foreign"SSL_connect"Ctypes.(t@->returningint)letaccept=foreign"SSL_accept"Ctypes.(t@->returningint)letset_bio=foreign"SSL_set_bio"Ctypes.(t@->Bio.t@->Bio.t@->returningvoid)letread=foreign"SSL_read"Ctypes.(t@->ptrchar@->int@->returningint)letwrite=foreign"SSL_write"Ctypes.(t@->string@->int@->returningint)letset_verify=foreign"SSL_set_verify"Ctypes.(t@->int@->ptrvoid@->returningvoid);;letset_cipher_list=foreign"SSL_set_cipher_list"Ctypes.(t@->string@->returningint);;letget_cipher_list=foreign"SSL_get_cipher_list"Ctypes.(t@->int@->returningstring_opt);;letset1_groups_list=foreign"SSL_set1_groups_list"Ctypes.(t@->string@->returningint);;(* free with X509_free() (source: manpage of SSL_get_peer_certificate(3)) *)letget_peer_certificate=foreign"SSL_get_peer_certificate"Ctypes.(t@->returningX509.t_opt);;letget_verify_result=foreign"SSL_get_verify_result"Ctypes.(t@->returninglong)letget_version=foreign"SSL_get_version"Ctypes.(t@->returningstring)letset_session=foreign"SSL_set_session"Ctypes.(t@->Ssl_session.t@->returningint);;letsession_reused=foreign"SSL_session_reused"Ctypes.(t@->returningint)(* free with SSL_session_free() (source: manpage of SSL_get1_session(3)) *)letget1_session=foreign"SSL_get1_session"Ctypes.(t@->returningSsl_session.t_opt);;letcheck_private_key=foreign"SSL_check_private_key"Ctypes.(t@->returningint)letset_tlsext_host_name=foreign"SSL_set_tlsext_host_name"Ctypes.(t@->ptrchar@->returningint);;letpem_peer_certificate_chain=foreign"async_ssl__pem_peer_certificate_chain"Ctypes.(t@->returning(ptr_optchar));;letfree_pem_peer_certificate_chain=foreign"async_ssl__free_pem_peer_certificate_chain"Ctypes.(ptrchar@->returningvoid);;letget_alpn_selected=foreign"SSL_get0_alpn_selected"Ctypes.(t@->ptr(ptrchar)@->ptrint@->returningvoid);;endend