From 65f4512855ec11891a10c0c28694d54b73de1df5 Mon Sep 17 00:00:00 2001 From: Pau Ruiz Safont Date: Wed, 6 Jul 2022 19:42:12 +0100 Subject: [PATCH 01/19] Add license to opam metadata (#80) I'm unsure whether this SPDX identifier is correct as it also has an exception for OpenSSL, there's a similar exception, but mentions OpenVPN explicitely: https://spdx.org/licenses/exceptions-index.html I could add a "WITH openssl-exception", but this doesn't have a meaning in the SPDX world and some parsers might complain about an invalid license --- ssl.opam | 1 + 1 file changed, 1 insertion(+) diff --git a/ssl.opam b/ssl.opam index fc2e632..16983bb 100644 --- a/ssl.opam +++ b/ssl.opam @@ -5,6 +5,7 @@ maintainer: "Samuel Mimram " homepage: "https://github.com/savonet/ocaml-ssl" dev-repo: "git+https://github.com/savonet/ocaml-ssl.git" bug-reports: "https://github.com/savonet/ocaml-ssl/issues" +license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ ["dune" "subst"] {pinned} ["dune" "build" "-p" name "-j" jobs] From 72da2cff9564607f25aac80ae322bfe15b88628d Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Mon, 18 Jul 2022 20:37:16 +0100 Subject: [PATCH 02/19] OCaml 5.0 fix: eliminate out-of-heap pointer for `client_verify_callback` (#83) * Box client_verify_callback OCaml 5.0 doesn't permit out-of-heap pointers. * Strict compatibility with OCaml 4.x * Add Changes --- CHANGES.md | 4 ++++ src/ssl_stubs.c | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index b531481..b45b6d3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,10 @@ - Add `digest` function (#65, #66). - Restore compatibility with openssl < 1.1.0 (#73). - Improved compatibility with OCaml 5 (#79). +- Fix `client_verify_callback` for `NO_NAKED_POINTERS` mode. A user-provided + verification function in C remains an out-of-heap pointer for 4.x for + compatibility, but is boxed for OCaml 5.x or 4.x when configured with + `--disable-naked-pointers`. (#83) 0.5.10 (2021-02-01) ====== diff --git a/src/ssl_stubs.c b/src/ssl_stubs.c index 2822d81..69beca1 100644 --- a/src/ssl_stubs.c +++ b/src/ssl_stubs.c @@ -59,6 +59,9 @@ #endif static int client_verify_callback(int, X509_STORE_CTX *); +#ifdef NO_NAKED_POINTERS +static value vclient_verify_callback = Val_int(0); +#endif static DH *load_dh_param(const char *dhfile); /******************* @@ -561,7 +564,16 @@ CAMLprim value ocaml_ssl_digest(value vevp, value vcert) CAMLprim value ocaml_ssl_get_client_verify_callback_ptr(value unit) { +#ifdef NO_NAKED_POINTERS + if (Is_long(vclient_verify_callback)) { + vclient_verify_callback = caml_alloc_shr(1, Abstract_tag); + *((int(**) (int, X509_STORE_CTX*))Data_abstract_val(vclient_verify_callback)) = client_verify_callback; + caml_register_generational_global_root(&vclient_verify_callback); + } + return vclient_verify_callback; +#else return (value)client_verify_callback; +#endif } static int client_verify_callback_verbose = 1; @@ -610,7 +622,16 @@ CAMLprim value ocaml_ssl_ctx_set_verify(value context, value vmode, value vcallb } if (Is_block(vcallback)) + { +#ifdef NO_NAKED_POINTERS + vcallback = Field(vcallback, 0); + if (!Is_block(vcallback) || Tag_val(vcallback) != Abstract_tag || Wosize_val(vcallback) != 1) + caml_invalid_argument("callback"); + callback = *((int(**) (int, X509_STORE_CTX*))Data_abstract_val(vcallback)); +#else callback = (int(*) (int, X509_STORE_CTX*))Field(vcallback, 0); +#endif + } caml_enter_blocking_section(); SSL_CTX_set_verify(ctx, mode, callback); From c4535472003d49a583f5c2ffdf8a5469c61d6384 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Wed, 20 Jul 2022 10:44:42 -0700 Subject: [PATCH 03/19] tag 0.5.11 --- CHANGES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b45b6d3..bd346be 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,5 @@ -0.5.11 (unreleased) -====== +0.5.11 +===== - Add `digest` function (#65, #66). - Restore compatibility with openssl < 1.1.0 (#73). From 924f60773244adfd9c21524ab905e4e3ea67a249 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Wed, 20 Jul 2022 10:47:17 -0700 Subject: [PATCH 04/19] opam file too --- ssl.opam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssl.opam b/ssl.opam index 16983bb..6a2f74c 100644 --- a/ssl.opam +++ b/ssl.opam @@ -1,6 +1,6 @@ opam-version: "2.0" name: "ssl" -version: "0.5.10" +version: "0.5.11" maintainer: "Samuel Mimram " homepage: "https://github.com/savonet/ocaml-ssl" dev-repo: "git+https://github.com/savonet/ocaml-ssl.git" From c8d297acc651808dc0f08efee6c415993d5c2d2b Mon Sep 17 00:00:00 2001 From: Kate Date: Wed, 20 Jul 2022 18:52:30 +0100 Subject: [PATCH 05/19] Fix calls to dune subst (#85) See https://github.com/ocaml/dune/pull/3647 --- ssl.opam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssl.opam b/ssl.opam index 6a2f74c..1b2b57b 100644 --- a/ssl.opam +++ b/ssl.opam @@ -7,7 +7,7 @@ dev-repo: "git+https://github.com/savonet/ocaml-ssl.git" bug-reports: "https://github.com/savonet/ocaml-ssl/issues" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ - ["dune" "subst"] {pinned} + ["dune" "subst"] {dev} ["dune" "build" "-p" name "-j" jobs] ] depends: [ From a631766ae7d1913ae50468d94dd077f619dec84f Mon Sep 17 00:00:00 2001 From: Docker Date: Thu, 1 Apr 2021 20:13:37 +0000 Subject: [PATCH 06/19] Implement SSL_CTX_add_extra_chain_cert() --- src/ssl.ml | 2 ++ src/ssl.mli | 5 +++++ src/ssl_stubs.c | 20 ++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/ssl.ml b/src/ssl.ml index 01990bd..5e7ec46 100644 --- a/src/ssl.ml +++ b/src/ssl.ml @@ -153,6 +153,8 @@ type context_type = external create_context : protocol -> context_type -> context = "ocaml_ssl_create_context" +external add_extra_chain_cert : context -> string -> unit = "ocaml_ssl_ctx_add_extra_chain_cert" + external use_certificate : context -> string -> string -> unit = "ocaml_ssl_ctx_use_certificate" external use_certificate_from_string : context -> string -> string -> unit = "ocaml_ssl_ctx_use_certificate_from_string" diff --git a/src/ssl.mli b/src/ssl.mli index 8463f29..691d786 100644 --- a/src/ssl.mli +++ b/src/ssl.mli @@ -238,6 +238,11 @@ type context_type = (** Create a context. *) val create_context : protocol -> context_type -> context +(** Add an additional certificate to the extra chain certificates + * associated with the [ctx]. The value should be contents of the + * certificate as string in PEM format. *) +val add_extra_chain_cert : context -> string -> unit + (** [use_certificate ctx cert privkey] makes the context [ctx] use [cert] as * certificate's file name (in PEM format) and [privkey] as private key file * name. *) diff --git a/src/ssl_stubs.c b/src/ssl_stubs.c index 69beca1..e94b488 100644 --- a/src/ssl_stubs.c +++ b/src/ssl_stubs.c @@ -442,6 +442,26 @@ CAMLprim value ocaml_ssl_create_context(value protocol, value type) return block; } +CAMLprim value ocaml_ssl_ctx_add_extra_chain_cert(value context, value cert) { + CAMLparam2(context, cert); + SSL_CTX *ctx = Ctx_val(context); + const char *cert_data = String_val(cert); + int cert_data_length = caml_string_length(cert); + char buf[256]; + X509 *x509_cert = NULL; + BIO *cbio; + + cbio = BIO_new_mem_buf((void*)cert_data, cert_data_length); + x509_cert = PEM_read_bio_X509(cbio, NULL, 0, NULL); + if (NULL == x509_cert || SSL_CTX_add_extra_chain_cert(ctx, x509_cert) <= 0) + { + ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); + caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string(buf)); + } + + CAMLreturn(Val_unit); +} + CAMLprim value ocaml_ssl_ctx_use_certificate(value context, value cert, value privkey) { CAMLparam3(context, cert, privkey); From ffadc067135ca71744cd61eb958477c5b0383070 Mon Sep 17 00:00:00 2001 From: Firgeis Date: Tue, 6 Apr 2021 12:25:51 +0000 Subject: [PATCH 07/19] Implement `add_cert_to_store` verify peer certificate CA --- src/ssl.ml | 2 ++ src/ssl.mli | 10 ++++++++-- src/ssl_stubs.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/ssl.ml b/src/ssl.ml index 5e7ec46..4d56a47 100644 --- a/src/ssl.ml +++ b/src/ssl.ml @@ -155,6 +155,8 @@ external create_context : protocol -> context_type -> context = "ocaml_ssl_creat external add_extra_chain_cert : context -> string -> unit = "ocaml_ssl_ctx_add_extra_chain_cert" +external add_cert_to_store : context -> string -> unit = "ocaml_ssl_ctx_add_cert_to_store" + external use_certificate : context -> string -> string -> unit = "ocaml_ssl_ctx_use_certificate" external use_certificate_from_string : context -> string -> string -> unit = "ocaml_ssl_ctx_use_certificate_from_string" diff --git a/src/ssl.mli b/src/ssl.mli index 691d786..f976da1 100644 --- a/src/ssl.mli +++ b/src/ssl.mli @@ -239,10 +239,16 @@ type context_type = val create_context : protocol -> context_type -> context (** Add an additional certificate to the extra chain certificates - * associated with the [ctx]. The value should be contents of the - * certificate as string in PEM format. *) + associated with the [ctx]. Extra chain certificates will be + sent to the peer for verification and are sent in order following the + end entity certificate. The value should be contents of the + certificate as string in PEM format. *) val add_extra_chain_cert : context -> string -> unit +(** Add a certificate to the [ctx] trust storage. The value should be contents + of the certificate as string in PEM format. *) +val add_cert_to_store : context -> string -> unit + (** [use_certificate ctx cert privkey] makes the context [ctx] use [cert] as * certificate's file name (in PEM format) and [privkey] as private key file * name. *) diff --git a/src/ssl_stubs.c b/src/ssl_stubs.c index e94b488..fb2bfdf 100644 --- a/src/ssl_stubs.c +++ b/src/ssl_stubs.c @@ -451,13 +451,41 @@ CAMLprim value ocaml_ssl_ctx_add_extra_chain_cert(value context, value cert) { X509 *x509_cert = NULL; BIO *cbio; + caml_enter_blocking_section(); cbio = BIO_new_mem_buf((void*)cert_data, cert_data_length); x509_cert = PEM_read_bio_X509(cbio, NULL, 0, NULL); if (NULL == x509_cert || SSL_CTX_add_extra_chain_cert(ctx, x509_cert) <= 0) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); + caml_leave_blocking_section(); + caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string(buf)); + } + caml_leave_blocking_section(); + + CAMLreturn(Val_unit); +} + +CAMLprim value ocaml_ssl_ctx_add_cert_to_store(value context, value cert) { + CAMLparam2(context,cert); + SSL_CTX *ctx = Ctx_val(context); + const char *cert_data = String_val(cert); + int cert_data_length = caml_string_length(cert); + char buf[256]; + X509 *x509_cert = NULL; + BIO *cbio; + + caml_enter_blocking_section(); + cbio = BIO_new_mem_buf((void*)cert_data, cert_data_length); + x509_cert = PEM_read_bio_X509(cbio, NULL, 0, NULL); + + X509_STORE *store = SSL_CTX_get_cert_store(ctx); + + if (NULL == x509_cert || X509_STORE_add_cert(store, x509_cert) <= 0) { + ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); + caml_leave_blocking_section(); caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string(buf)); } + caml_leave_blocking_section(); CAMLreturn(Val_unit); } From d28f2b5e09d4a48992d0d053388446221c0f4bfb Mon Sep 17 00:00:00 2001 From: Firgeis Date: Wed, 7 Apr 2021 19:59:17 +0000 Subject: [PATCH 08/19] Generalize `use_certificate_from_string` to any key type not just RSA --- src/ssl_stubs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ssl_stubs.c b/src/ssl_stubs.c index fb2bfdf..37134d3 100644 --- a/src/ssl_stubs.c +++ b/src/ssl_stubs.c @@ -531,7 +531,7 @@ CAMLprim value ocaml_ssl_ctx_use_certificate_from_string(value context, value ce int privkey_data_length = caml_string_length(privkey); char buf[256]; X509 *x509_cert = NULL; - RSA *rsa = NULL; + EVP_PKEY *pkey = NULL; BIO *cbio, *kbio; cbio = BIO_new_mem_buf((void*)cert_data, cert_data_length); @@ -543,8 +543,8 @@ CAMLprim value ocaml_ssl_ctx_use_certificate_from_string(value context, value ce } kbio = BIO_new_mem_buf((void*)privkey_data, privkey_data_length); - rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL); - if (NULL == rsa || SSL_CTX_use_RSAPrivateKey(ctx, rsa) <= 0) + pkey = PEM_read_bio_PrivateKey(kbio, NULL, 0, NULL); + if (NULL == pkey || SSL_CTX_use_PrivateKey(ctx, pkey) <= 0) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); caml_raise_with_arg(*caml_named_value("ssl_exn_private_key_error"), caml_copy_string(buf)); From be41e5e466e8a604d79d1b25dd3fed9ea5c78939 Mon Sep 17 00:00:00 2001 From: Firgeis Date: Thu, 6 May 2021 23:47:33 +0000 Subject: [PATCH 09/19] Add `set_ip` through `X509_VERIFY_PARAM_set1_ip_asc()` sets the expected IP to be verified on the socket --- src/ssl.ml | 2 ++ src/ssl.mli | 5 +++++ src/ssl_stubs.c | 13 +++++++++++++ 3 files changed, 20 insertions(+) diff --git a/src/ssl.ml b/src/ssl.ml index 4d56a47..3f68d4f 100644 --- a/src/ssl.ml +++ b/src/ssl.ml @@ -259,6 +259,8 @@ external set_hostflags : socket -> x509_check_flag list -> unit = "ocaml_ssl_set external set_host : socket -> string -> unit = "ocaml_ssl_set1_host" +external set_ip : socket -> string -> unit = "ocaml_ssl_set1_ip" + external write : socket -> Bytes.t -> int -> int -> int = "ocaml_ssl_write" external write_substring : socket -> string -> int -> int -> int = "ocaml_ssl_write" diff --git a/src/ssl.mli b/src/ssl.mli index f976da1..301ce42 100644 --- a/src/ssl.mli +++ b/src/ssl.mli @@ -456,6 +456,11 @@ val set_hostflags : socket -> x509_check_flag list -> unit (* Set the expected host name to be verified. *) val set_host : socket -> string -> unit +(** Set the expected ip address to be verified. Ip address is dotted decimal quad + for IPv4 and colon-separated hexadecimal for IPv6. + The condensed "::" notation is supported for IPv6 addresses. *) +val set_ip : socket -> string -> unit + (** Get the file descriptor associated with a socket. It is primarly useful for [select]ing on it; you should not write or read on it. *) val file_descr_of_socket : socket -> Unix.file_descr diff --git a/src/ssl_stubs.c b/src/ssl_stubs.c index 37134d3..661b381 100644 --- a/src/ssl_stubs.c +++ b/src/ssl_stubs.c @@ -1536,6 +1536,19 @@ CAMLprim value ocaml_ssl_set1_host(value socket, value host) CAMLreturn(Val_unit); } +CAMLprim value ocaml_ssl_set1_ip(value socket, value ip) +{ + CAMLparam2(socket, ip); + SSL *ssl = SSL_val(socket); + const char *ipval = String_val (ip); + + caml_enter_blocking_section(); + X509_VERIFY_PARAM_set1_ip_asc (SSL_get0_param(ssl), ipval); + caml_leave_blocking_section(); + + CAMLreturn(Val_unit); +} + CAMLprim value ocaml_ssl_write(value socket, value buffer, value start, value length) { CAMLparam2(socket, buffer); From fbbb8b7a4dc4ff3d1f3f41c4d9db6c170236b459 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sun, 24 Jul 2022 01:49:38 -0700 Subject: [PATCH 10/19] Add changelog entries for #71 --- CHANGES.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index bd346be..df06504 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,14 @@ +Unreleased +===== + +- Add a few verification functions (#71): + - `add_extra_chain_cert` to send additional chain certificates to the peer. + - `add_cert_to_store`: to allow verification of the peer certificate CA. + - `set_ip`: sets the expected IP address to be verified on a SSL socket. + +- Improve `use_certificate_from_string` (#71) to read any type of key (rather + than just RSA). + 0.5.11 ===== From a512a8200d35bfb82e96af28cd9a1e7cbe884486 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Thu, 11 Aug 2022 15:36:43 -0700 Subject: [PATCH 11/19] Rename caml_{enter,leave}_blocking_section to caml_{release,acquire}_runtime_system (#88) --- src/ssl_stubs.c | 238 ++++++++++++++++++++++++------------------------ 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/src/ssl_stubs.c b/src/ssl_stubs.c index 661b381..3c5b913 100644 --- a/src/ssl_stubs.c +++ b/src/ssl_stubs.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include @@ -292,7 +292,7 @@ static const SSL_METHOD *get_method(int protocol, int type) { const SSL_METHOD *method = NULL; - caml_enter_blocking_section(); + caml_release_runtime_system(); switch (protocol) { case 0: @@ -406,11 +406,11 @@ static const SSL_METHOD *get_method(int protocol, int type) break; default: - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_invalid_argument("Unknown method (this should not have happened, please report)."); break; } - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (method == NULL) caml_raise_constant(*caml_named_value("ssl_exn_method_error")); @@ -424,18 +424,18 @@ CAMLprim value ocaml_ssl_create_context(value protocol, value type) SSL_CTX *ctx; const SSL_METHOD *method = get_method(Int_val(protocol), Int_val(type)); - caml_enter_blocking_section(); + caml_release_runtime_system(); ctx = SSL_CTX_new(method); if (!ctx) { - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_constant(*caml_named_value("ssl_exn_context_error")); } /* In non-blocking mode, accept a buffer with a different address on a write retry (since the GC may need to move it). In blocking mode, hide SSL_ERROR_WANT_(READ|WRITE) from us. */ SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); block = caml_alloc_custom(&ctx_ops, sizeof(SSL_CTX*), 0, 1); Ctx_val(block) = ctx; @@ -451,16 +451,16 @@ CAMLprim value ocaml_ssl_ctx_add_extra_chain_cert(value context, value cert) { X509 *x509_cert = NULL; BIO *cbio; - caml_enter_blocking_section(); + caml_release_runtime_system(); cbio = BIO_new_mem_buf((void*)cert_data, cert_data_length); x509_cert = PEM_read_bio_X509(cbio, NULL, 0, NULL); if (NULL == x509_cert || SSL_CTX_add_extra_chain_cert(ctx, x509_cert) <= 0) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string(buf)); } - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -474,7 +474,7 @@ CAMLprim value ocaml_ssl_ctx_add_cert_to_store(value context, value cert) { X509 *x509_cert = NULL; BIO *cbio; - caml_enter_blocking_section(); + caml_release_runtime_system(); cbio = BIO_new_mem_buf((void*)cert_data, cert_data_length); x509_cert = PEM_read_bio_X509(cbio, NULL, 0, NULL); @@ -482,10 +482,10 @@ CAMLprim value ocaml_ssl_ctx_add_cert_to_store(value context, value cert) { if (NULL == x509_cert || X509_STORE_add_cert(store, x509_cert) <= 0) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string(buf)); } - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -498,25 +498,25 @@ CAMLprim value ocaml_ssl_ctx_use_certificate(value context, value cert, value pr const char *privkey_name = String_val(privkey); char buf[256]; - caml_enter_blocking_section(); + caml_release_runtime_system(); if (SSL_CTX_use_certificate_chain_file(ctx, cert_name) <= 0) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string(buf)); } if (SSL_CTX_use_PrivateKey_file(ctx, privkey_name, SSL_FILETYPE_PEM) <= 0) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_with_arg(*caml_named_value("ssl_exn_private_key_error"), caml_copy_string(buf)); } if (!SSL_CTX_check_private_key(ctx)) { - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_constant(*caml_named_value("ssl_exn_unmatching_keys")); } - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -563,9 +563,9 @@ CAMLprim value ocaml_ssl_get_verify_result(value socket) int ans; SSL *ssl = SSL_val(socket); - caml_enter_blocking_section(); + caml_release_runtime_system(); ans = SSL_get_verify_result(ssl); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_int(ans)); } @@ -575,9 +575,9 @@ CAMLprim value ocaml_ssl_get_verify_error_string(value verrn) int errn = Int_val(verrn); const char *error_string; - caml_enter_blocking_section(); + caml_release_runtime_system(); error_string = X509_verify_cert_error_string(errn); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); return caml_copy_string(error_string); } @@ -597,9 +597,9 @@ CAMLprim value ocaml_ssl_digest(value vevp, value vcert) size_t digest_size = EVP_MD_size(evp); assert(digest_size <= sizeof(buf)); X509 *x509 = *((X509 **) Data_custom_val(vcert)); - caml_enter_blocking_section(); + caml_release_runtime_system(); int status = X509_digest(x509, evp, (unsigned char*)buf, NULL); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (0 == status) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); @@ -681,9 +681,9 @@ CAMLprim value ocaml_ssl_ctx_set_verify(value context, value vmode, value vcallb #endif } - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_CTX_set_verify(ctx, mode, callback); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -696,9 +696,9 @@ CAMLprim value ocaml_ssl_ctx_set_verify_depth(value context, value vdepth) if (depth < 0) caml_invalid_argument("depth"); - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_CTX_set_verify_depth(ctx, depth); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); return Val_unit; } @@ -711,17 +711,17 @@ CAMLprim value ocaml_ssl_ctx_set_client_CA_list_from_file(value context, value v STACK_OF(X509_NAME) *cert_names; char buf[256]; - caml_enter_blocking_section(); + caml_release_runtime_system(); cert_names = SSL_load_client_CA_file(filename); if (cert_names != 0) SSL_CTX_set_client_CA_list(ctx, cert_names); else { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string(buf)); } - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -764,9 +764,9 @@ CAMLprim value ocaml_ssl_ctx_set_alpn_protos(value context, value vprotos) unsigned char protos[total_len]; build_alpn_protocol_buffer(vprotos, protos); - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_CTX_set_alpn_protos(ctx, protos, sizeof(protos)); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -815,13 +815,13 @@ static int alpn_select_cb(SSL *ssl, int len; - caml_leave_blocking_section(); + caml_acquire_runtime_system(); protocol_list = build_alpn_protocol_list(in, inlen); selected_protocol_opt = caml_callback(*((value*)arg), protocol_list); if(selected_protocol_opt == Val_none) { - caml_enter_blocking_section(); + caml_release_runtime_system(); return SSL_TLSEXT_ERR_NOACK; } @@ -829,7 +829,7 @@ static int alpn_select_cb(SSL *ssl, len = caml_string_length(selected_protocol); *out = String_val(selected_protocol); *outlen = len; - caml_enter_blocking_section(); + caml_release_runtime_system(); return SSL_TLSEXT_ERR_OK; } @@ -845,9 +845,9 @@ CAMLprim value ocaml_ssl_ctx_set_alpn_select_callback(value context, value cb) *select_cb = cb; caml_register_global_root(select_cb); - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, select_cb); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -872,12 +872,12 @@ static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata) value s; int len; - caml_leave_blocking_section(); + caml_acquire_runtime_system(); s = caml_callback(*((value*)userdata), Val_int(rwflag)); len = caml_string_length(s); assert(len <= size); memcpy(buf, String_val(s), len); - caml_enter_blocking_section(); + caml_release_runtime_system(); return len; } @@ -893,10 +893,10 @@ CAMLprim value ocaml_ssl_ctx_set_default_passwd_cb(value context, value cb) *pcb = cb; caml_register_global_root(pcb); - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(ctx, pcb); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -923,13 +923,13 @@ CAMLprim value ocaml_ssl_ctx_set_cipher_list(value context, value ciphers_string if(*ciphers == 0) caml_raise_constant(*caml_named_value("ssl_exn_cipher_error")); - caml_enter_blocking_section(); + caml_release_runtime_system(); if(SSL_CTX_set_cipher_list(ctx, ciphers) != 1) { - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_constant(*caml_named_value("ssl_exn_cipher_error")); } - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -939,9 +939,9 @@ CAMLprim value ocaml_ssl_disable_protocols(value context, value protocol_list) CAMLparam2(context, protocol_list); SSL_CTX *ctx = Ctx_val(context); int flags = caml_convert_flag_list(protocol_list, protocol_flags); - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_CTX_set_options(ctx, flags); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -953,9 +953,9 @@ CAMLprim value ocaml_ssl_version(value socket) int version; int ret; - caml_enter_blocking_section(); + caml_release_runtime_system(); version = SSL_version(ssl); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); switch(version) { case SSL3_VERSION: @@ -992,9 +992,9 @@ CAMLprim value ocaml_ssl_get_current_cipher(value socket) CAMLparam1(socket); SSL *ssl = SSL_val(socket); - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_CIPHER *cipher = (SSL_CIPHER*)SSL_get_current_cipher(ssl); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (!cipher) caml_raise_constant(*caml_named_value("ssl_exn_cipher_error")); @@ -1006,9 +1006,9 @@ CAMLprim value ocaml_ssl_get_cipher_description(value vcipher) char buf[1024]; SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher; - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_CIPHER_description(cipher, buf, 1024); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); return caml_copy_string(buf); } @@ -1018,9 +1018,9 @@ CAMLprim value ocaml_ssl_get_cipher_name(value vcipher) const char *name; SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher; - caml_enter_blocking_section(); + caml_release_runtime_system(); name = SSL_CIPHER_get_name(cipher); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); return caml_copy_string(name); } @@ -1030,9 +1030,9 @@ CAMLprim value ocaml_ssl_get_cipher_version(value vcipher) const char *version; SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher; - caml_enter_blocking_section(); + caml_release_runtime_system(); version = SSL_CIPHER_get_version(cipher); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); return caml_copy_string(version); } @@ -1048,18 +1048,18 @@ CAMLprim value ocaml_ssl_ctx_init_dh_from_file(value context, value dh_file_path caml_raise_constant(*caml_named_value("ssl_exn_diffie_hellman_error")); dh = load_dh_param(dh_cfile_path); - caml_enter_blocking_section(); + caml_release_runtime_system(); if (dh != NULL){ if(SSL_CTX_set_tmp_dh(ctx,dh) != 1){ - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_constant(*caml_named_value("ssl_exn_diffie_hellman_error")); } SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); DH_free(dh); } else{ - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_constant(*caml_named_value("ssl_exn_diffie_hellman_error")); } CAMLreturn(Val_unit); @@ -1082,19 +1082,19 @@ CAMLprim value ocaml_ssl_ctx_init_ec_from_named_curve(value context, value curve caml_raise_constant(*caml_named_value("ssl_exn_ec_curve_error")); } - caml_enter_blocking_section(); + caml_release_runtime_system(); ecdh = EC_KEY_new_by_curve_name(nid); if(ecdh != NULL){ if(SSL_CTX_set_tmp_ecdh(ctx,ecdh) != 1){ - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_constant(*caml_named_value("ssl_exn_ec_curve_error")); } SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); EC_KEY_free(ecdh); } else{ - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_constant(*caml_named_value("ssl_exn_ec_curve_error")); } CAMLreturn(Val_unit); @@ -1140,16 +1140,16 @@ CAMLprim value ocaml_ssl_read_certificate(value vfilename) if((fh = fopen(filename, "r")) == NULL) caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string("couldn't open certificate file")); - caml_enter_blocking_section(); + caml_release_runtime_system(); if((PEM_read_X509(fh, &cert, 0, 0)) == NULL) { fclose(fh); ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string(buf)); } fclose(fh); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); block = caml_alloc_custom(&cert_ops, sizeof(X509*), 0, 1); Cert_val(block) = cert; @@ -1167,16 +1167,16 @@ CAMLprim value ocaml_ssl_write_certificate(value vfilename, value certificate) if((fh = fopen(filename, "w")) == NULL) caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string("couldn't open certificate file")); - caml_enter_blocking_section(); + caml_release_runtime_system(); if(PEM_write_X509(fh, cert) == 0) { fclose(fh); ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_with_arg(*caml_named_value("ssl_exn_certificate_error"), caml_copy_string(buf)); } fclose(fh); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -1187,9 +1187,9 @@ CAMLprim value ocaml_ssl_get_certificate(value socket) SSL *ssl = SSL_val(socket); char buf[256]; - caml_enter_blocking_section(); + caml_release_runtime_system(); X509 *cert = SSL_get_peer_certificate(ssl); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (!cert) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); @@ -1207,9 +1207,9 @@ CAMLprim value ocaml_ssl_get_issuer(value certificate) CAMLparam1(certificate); X509 *cert = Cert_val(certificate); - caml_enter_blocking_section(); + caml_release_runtime_system(); char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (!issuer) caml_raise_not_found (); CAMLreturn(caml_copy_string(issuer)); @@ -1220,9 +1220,9 @@ CAMLprim value ocaml_ssl_get_subject(value certificate) CAMLparam1(certificate); X509 *cert = Cert_val(certificate); - caml_enter_blocking_section(); + caml_release_runtime_system(); char *subject = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (subject == NULL) caml_raise_not_found (); CAMLreturn(caml_copy_string(subject)); @@ -1251,9 +1251,9 @@ CAMLprim value ocaml_ssl_get_start_date(value certificate) X509 *cert = Cert_val(certificate); struct tm t; - caml_enter_blocking_section(); + caml_release_runtime_system(); ASN1_TIME_to_tm(X509_get0_notBefore(cert), &t); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(alloc_tm(&t)); } @@ -1264,9 +1264,9 @@ CAMLprim value ocaml_ssl_get_expiration_date(value certificate) X509 *cert = Cert_val(certificate); struct tm t; - caml_enter_blocking_section(); + caml_release_runtime_system(); ASN1_TIME_to_tm(X509_get0_notAfter(cert), &t); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(alloc_tm(&t)); } @@ -1295,13 +1295,13 @@ CAMLprim value ocaml_ssl_ctx_load_verify_locations(value context, value ca_file, if(*CApath == 0) CApath = NULL; - caml_enter_blocking_section(); + caml_release_runtime_system(); if(SSL_CTX_load_verify_locations(ctx, CAfile, CApath) != 1) { - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_invalid_argument("cafile or capath"); } - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -1312,9 +1312,9 @@ CAMLprim value ocaml_ssl_ctx_set_default_verify_paths(value context) int ret; SSL_CTX *ctx = Ctx_val(context); - caml_enter_blocking_section(); + caml_release_runtime_system(); ret = SSL_CTX_set_default_verify_paths(ctx); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_bool(ret)); } @@ -1329,9 +1329,9 @@ CAMLprim value ocaml_ssl_get_file_descr(value socket) SSL *ssl = SSL_val(socket); int fd; - caml_enter_blocking_section(); + caml_release_runtime_system(); fd = SSL_get_fd(ssl); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_int(fd)); } @@ -1352,15 +1352,15 @@ CAMLprim value ocaml_ssl_embed_socket(value socket_, value context) if (socket < 0) caml_raise_constant(*caml_named_value("ssl_exn_invalid_socket")); - caml_enter_blocking_section(); + caml_release_runtime_system(); ssl = SSL_new(ctx); if (!ssl) { - caml_leave_blocking_section(); + caml_acquire_runtime_system(); caml_raise_constant(*caml_named_value("ssl_exn_handler_error")); } SSL_set_fd(ssl, socket); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); SSL_val(block) = ssl; CAMLreturn(block); @@ -1373,9 +1373,9 @@ CAMLprim value ocaml_ssl_set_client_SNI_hostname(value socket, value vhostname) SSL *ssl = SSL_val(socket); const char *hostname = String_val(vhostname); - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_set_tlsext_host_name(ssl, hostname); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -1398,9 +1398,9 @@ CAMLprim value ocaml_ssl_set_alpn_protos(value socket, value vprotos) unsigned char protos[total_len]; build_alpn_protocol_buffer(vprotos, protos); - caml_enter_blocking_section(); + caml_release_runtime_system(); SSL_set_alpn_protos(ssl, protos, sizeof(protos)); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -1454,10 +1454,10 @@ CAMLprim value ocaml_ssl_connect(value socket) int ret, err; SSL *ssl = SSL_val(socket); - caml_enter_blocking_section(); + caml_release_runtime_system(); ret = SSL_connect(ssl); err = SSL_get_error(ssl, ret); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (err != SSL_ERROR_NONE) caml_raise_with_arg(*caml_named_value("ssl_exn_connection_error"), Val_int(err)); @@ -1470,9 +1470,9 @@ CAMLprim value ocaml_ssl_verify(value socket) SSL *ssl = SSL_val(socket); long ans; - caml_enter_blocking_section(); + caml_release_runtime_system(); ans = SSL_get_verify_result(ssl); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (ans != 0) { @@ -1516,9 +1516,9 @@ CAMLprim value ocaml_ssl_set_hostflags(value socket, value flag_lst) flag_lst = Field(flag_lst, 1); } - caml_enter_blocking_section(); + caml_release_runtime_system(); X509_VERIFY_PARAM_set_hostflags(SSL_get0_param(ssl), flags); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -1529,9 +1529,9 @@ CAMLprim value ocaml_ssl_set1_host(value socket, value host) SSL *ssl = SSL_val(socket); const char *hostname = String_val (host); - caml_enter_blocking_section(); + caml_release_runtime_system(); X509_VERIFY_PARAM_set1_host (SSL_get0_param(ssl), hostname, 0); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -1542,9 +1542,9 @@ CAMLprim value ocaml_ssl_set1_ip(value socket, value ip) SSL *ssl = SSL_val(socket); const char *ipval = String_val (ip); - caml_enter_blocking_section(); + caml_release_runtime_system(); X509_VERIFY_PARAM_set1_ip_asc (SSL_get0_param(ssl), ipval); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -1561,11 +1561,11 @@ CAMLprim value ocaml_ssl_write(value socket, value buffer, value start, value le caml_invalid_argument("Buffer too short."); memmove(buf, (char*)String_val(buffer) + Int_val(start), buflen); - caml_enter_blocking_section(); + caml_release_runtime_system(); ERR_clear_error(); ret = SSL_write(ssl, buf, buflen); err = SSL_get_error(ssl, ret); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); free(buf); if (err != SSL_ERROR_NONE) @@ -1588,11 +1588,11 @@ CAMLprim value ocaml_ssl_write_bigarray(value socket, value buffer, value start, if (Int_val(start) + Int_val(length) > ba->dim[0]) caml_invalid_argument("Ssl.write_bigarray: buffer too short."); - caml_enter_blocking_section(); + caml_release_runtime_system(); ERR_clear_error(); ret = SSL_write(ssl, buf, Int_val(length)); err = SSL_get_error(ssl, ret); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (err != SSL_ERROR_NONE) caml_raise_with_arg(*caml_named_value("ssl_exn_write_error"), Val_int(err)); @@ -1635,11 +1635,11 @@ CAMLprim value ocaml_ssl_read(value socket, value buffer, value start, value len if (Int_val(start) + Int_val(length) > caml_string_length(buffer)) caml_invalid_argument("Buffer too short."); - caml_enter_blocking_section(); + caml_release_runtime_system(); ERR_clear_error(); ret = SSL_read(ssl, buf, buflen); err = SSL_get_error(ssl, ret); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); memmove(((char*)String_val(buffer)) + Int_val(start), buf, buflen); free(buf); @@ -1663,11 +1663,11 @@ CAMLprim value ocaml_ssl_read_into_bigarray(value socket, value buffer, value st if (Int_val(start) + Int_val(length) > ba->dim[0]) caml_invalid_argument("Ssl.read_into_bigarray: buffer too short."); - caml_enter_blocking_section(); + caml_release_runtime_system(); ERR_clear_error(); ret = SSL_read(ssl, buf, Int_val(length)); err = SSL_get_error(ssl, ret); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (err != SSL_ERROR_NONE) caml_raise_with_arg(*caml_named_value("ssl_exn_read_error"), Val_int(err)); @@ -1705,11 +1705,11 @@ CAMLprim value ocaml_ssl_accept(value socket) SSL *ssl = SSL_val(socket); int ret, err; - caml_enter_blocking_section(); + caml_release_runtime_system(); ERR_clear_error(); ret = SSL_accept(ssl); err = SSL_get_error(ssl, ret); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); if (err != SSL_ERROR_NONE) caml_raise_with_arg(*caml_named_value("ssl_exn_accept_error"), Val_int(err)); @@ -1722,14 +1722,14 @@ CAMLprim value ocaml_ssl_flush(value socket) SSL *ssl = SSL_val(socket); BIO *bio; - caml_enter_blocking_section(); + caml_release_runtime_system(); bio = SSL_get_wbio(ssl); if(bio) { /* TODO: raise an error */ assert(BIO_flush(bio) == 1); } - caml_leave_blocking_section(); + caml_acquire_runtime_system(); CAMLreturn(Val_unit); } @@ -1740,11 +1740,11 @@ CAMLprim value ocaml_ssl_shutdown(value socket) SSL *ssl = SSL_val(socket); int ret; - caml_enter_blocking_section(); + caml_release_runtime_system(); ret = SSL_shutdown(ssl); if (!ret) SSL_shutdown(ssl); - caml_leave_blocking_section(); + caml_acquire_runtime_system(); /* close(SSL_get_fd(SSL_val(socket))); */ CAMLreturn(Val_unit); From 16bf6cbee3fb4c660f0e19cb81f6769424c5129d Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Thu, 11 Aug 2022 16:38:53 -0700 Subject: [PATCH 12/19] Fix a segfault in `alpn_select_cb` under OCaml 5 (#89) * Fix a segfault in `alpn_select_cb` under OCaml 5 * add changes entry --- CHANGES.md | 2 ++ src/ssl_stubs.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index df06504..f2cdf69 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,8 @@ Unreleased - Improve `use_certificate_from_string` (#71) to read any type of key (rather than just RSA). +- Fix a segmentation fault in the ALPN selection callback under OCaml 5 (#89). + 0.5.11 ===== diff --git a/src/ssl_stubs.c b/src/ssl_stubs.c index 3c5b913..4abb4b8 100644 --- a/src/ssl_stubs.c +++ b/src/ssl_stubs.c @@ -803,25 +803,26 @@ static value build_alpn_protocol_list(const unsigned char *protocol_buffer, unsi CAMLreturn(protocol_list); } -static int alpn_select_cb(SSL *ssl, - const unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen, - void *arg) + +/* The `alpn_select_cb` function below acquires the runtime lock before calling + * this one. Some more info in https://github.com/ocaml/ocaml/issues/11485 */ +CAMLprim value caml_alpn_select_cb(SSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg) { CAMLparam0(); CAMLlocal3(protocol_list, selected_protocol, selected_protocol_opt); int len; - caml_acquire_runtime_system(); protocol_list = build_alpn_protocol_list(in, inlen); selected_protocol_opt = caml_callback(*((value*)arg), protocol_list); if(selected_protocol_opt == Val_none) { - caml_release_runtime_system(); return SSL_TLSEXT_ERR_NOACK; } @@ -829,11 +830,25 @@ static int alpn_select_cb(SSL *ssl, len = caml_string_length(selected_protocol); *out = String_val(selected_protocol); *outlen = len; - caml_release_runtime_system(); return SSL_TLSEXT_ERR_OK; } +static int alpn_select_cb(SSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg) +{ + int res; + caml_acquire_runtime_system(); + res = caml_alpn_select_cb(ssl, out, outlen, in, inlen, arg); + caml_release_runtime_system(); + + return res; +} + CAMLprim value ocaml_ssl_ctx_set_alpn_select_callback(value context, value cb) { CAMLparam2(context, cb); From e9bcc8b7612116bd99c370a8286a834af9843684 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Fri, 12 Aug 2022 10:16:55 -0700 Subject: [PATCH 13/19] FFI: fix missing `CAMLparamX` and `CAMLreturn` in the C FFI (#90) * FFI: fix missing `CAMLparamX` and `CAMLreturn` in the C FFI * changes entry * Fix gasche's suggestion --- CHANGES.md | 3 +-- src/ssl_stubs.c | 46 ++++++++++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f2cdf69..3131e3e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,11 +5,10 @@ Unreleased - `add_extra_chain_cert` to send additional chain certificates to the peer. - `add_cert_to_store`: to allow verification of the peer certificate CA. - `set_ip`: sets the expected IP address to be verified on a SSL socket. - - Improve `use_certificate_from_string` (#71) to read any type of key (rather than just RSA). - - Fix a segmentation fault in the ALPN selection callback under OCaml 5 (#89). +- Audit the C FFI and add `CAMLparamX` and `CAMLreturn` calls (#90). 0.5.11 ===== diff --git a/src/ssl_stubs.c b/src/ssl_stubs.c index 4abb4b8..6924d5f 100644 --- a/src/ssl_stubs.c +++ b/src/ssl_stubs.c @@ -221,6 +221,7 @@ static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *fil CAMLprim value ocaml_ssl_init(value use_threads) { + CAMLparam1(use_threads); int i; SSL_library_init(); @@ -250,14 +251,15 @@ CAMLprim value ocaml_ssl_init(value use_threads) CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function); } - return Val_unit; + CAMLreturn(Val_unit); } CAMLprim value ocaml_ssl_get_error_string(value unit) { + CAMLparam1(unit); char buf[256]; ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - return caml_copy_string(buf); + CAMLreturn(caml_copy_string(buf)); } @@ -420,7 +422,8 @@ static const SSL_METHOD *get_method(int protocol, int type) CAMLprim value ocaml_ssl_create_context(value protocol, value type) { - value block; + CAMLparam2(protocol, type); + CAMLlocal1(block); SSL_CTX *ctx; const SSL_METHOD *method = get_method(Int_val(protocol), Int_val(type)); @@ -439,7 +442,7 @@ CAMLprim value ocaml_ssl_create_context(value protocol, value type) block = caml_alloc_custom(&ctx_ops, sizeof(SSL_CTX*), 0, 1); Ctx_val(block) = ctx; - return block; + CAMLreturn(block); } CAMLprim value ocaml_ssl_ctx_add_extra_chain_cert(value context, value cert) { @@ -572,6 +575,7 @@ CAMLprim value ocaml_ssl_get_verify_result(value socket) CAMLprim value ocaml_ssl_get_verify_error_string(value verrn) { + CAMLparam1(verrn); int errn = Int_val(verrn); const char *error_string; @@ -579,7 +583,7 @@ CAMLprim value ocaml_ssl_get_verify_error_string(value verrn) error_string = X509_verify_cert_error_string(errn); caml_acquire_runtime_system(); - return caml_copy_string(error_string); + CAMLreturn(caml_copy_string(error_string)); } CAMLprim value ocaml_ssl_digest(value vevp, value vcert) @@ -612,15 +616,16 @@ CAMLprim value ocaml_ssl_digest(value vevp, value vcert) CAMLprim value ocaml_ssl_get_client_verify_callback_ptr(value unit) { + CAMLparam1(unit); #ifdef NO_NAKED_POINTERS if (Is_long(vclient_verify_callback)) { vclient_verify_callback = caml_alloc_shr(1, Abstract_tag); *((int(**) (int, X509_STORE_CTX*))Data_abstract_val(vclient_verify_callback)) = client_verify_callback; caml_register_generational_global_root(&vclient_verify_callback); } - return vclient_verify_callback; + CAMLreturn(vclient_verify_callback); #else - return (value)client_verify_callback; + CAMLreturn((value)client_verify_callback); #endif } @@ -690,6 +695,7 @@ CAMLprim value ocaml_ssl_ctx_set_verify(value context, value vmode, value vcallb CAMLprim value ocaml_ssl_ctx_set_verify_depth(value context, value vdepth) { + CAMLparam2(context, vdepth); SSL_CTX *ctx = Ctx_val(context); int depth = Int_val(vdepth); @@ -700,7 +706,7 @@ CAMLprim value ocaml_ssl_ctx_set_verify_depth(value context, value vdepth) SSL_CTX_set_verify_depth(ctx, depth); caml_acquire_runtime_system(); - return Val_unit; + CAMLreturn(Val_unit); } CAMLprim value ocaml_ssl_ctx_set_client_CA_list_from_file(value context, value vfilename) @@ -823,7 +829,7 @@ CAMLprim value caml_alpn_select_cb(SSL *ssl, if(selected_protocol_opt == Val_none) { - return SSL_TLSEXT_ERR_NOACK; + CAMLreturn(SSL_TLSEXT_ERR_NOACK); } selected_protocol = Field(selected_protocol_opt, 0); @@ -831,7 +837,7 @@ CAMLprim value caml_alpn_select_cb(SSL *ssl, *out = String_val(selected_protocol); *outlen = len; - return SSL_TLSEXT_ERR_OK; + CAMLreturn(SSL_TLSEXT_ERR_OK); } static int alpn_select_cb(SSL *ssl, @@ -1018,6 +1024,7 @@ CAMLprim value ocaml_ssl_get_current_cipher(value socket) CAMLprim value ocaml_ssl_get_cipher_description(value vcipher) { + CAMLparam1(vcipher); char buf[1024]; SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher; @@ -1025,11 +1032,12 @@ CAMLprim value ocaml_ssl_get_cipher_description(value vcipher) SSL_CIPHER_description(cipher, buf, 1024); caml_acquire_runtime_system(); - return caml_copy_string(buf); + CAMLreturn(caml_copy_string(buf)); } CAMLprim value ocaml_ssl_get_cipher_name(value vcipher) { + CAMLparam1(vcipher); const char *name; SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher; @@ -1037,11 +1045,12 @@ CAMLprim value ocaml_ssl_get_cipher_name(value vcipher) name = SSL_CIPHER_get_name(cipher); caml_acquire_runtime_system(); - return caml_copy_string(name); + CAMLreturn(caml_copy_string(name)); } CAMLprim value ocaml_ssl_get_cipher_version(value vcipher) { + CAMLparam1(vcipher); const char *version; SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher; @@ -1049,7 +1058,7 @@ CAMLprim value ocaml_ssl_get_cipher_version(value vcipher) version = SSL_CIPHER_get_version(cipher); caml_acquire_runtime_system(); - return caml_copy_string(version); + CAMLreturn(caml_copy_string(version)); } CAMLprim value ocaml_ssl_ctx_init_dh_from_file(value context, value dh_file_path) @@ -1072,11 +1081,11 @@ CAMLprim value ocaml_ssl_ctx_init_dh_from_file(value context, value dh_file_path SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); caml_acquire_runtime_system(); DH_free(dh); - } - else{ + } else { caml_acquire_runtime_system(); caml_raise_constant(*caml_named_value("ssl_exn_diffie_hellman_error")); } + CAMLreturn(Val_unit); } @@ -1146,7 +1155,8 @@ static struct custom_operations cert_ops = CAMLprim value ocaml_ssl_read_certificate(value vfilename) { - value block; + CAMLparam1(vfilename); + CAMLlocal1(block); const char *filename = String_val(vfilename); X509 *cert = NULL; FILE *fh = NULL; @@ -1168,7 +1178,7 @@ CAMLprim value ocaml_ssl_read_certificate(value vfilename) block = caml_alloc_custom(&cert_ops, sizeof(X509*), 0, 1); Cert_val(block) = cert; - return block; + CAMLreturn(block); } CAMLprim value ocaml_ssl_write_certificate(value vfilename, value certificate) @@ -1353,7 +1363,7 @@ CAMLprim value ocaml_ssl_get_file_descr(value socket) CAMLprim value ocaml_ssl_embed_socket(value socket_, value context) { - CAMLparam1(context); + CAMLparam2(socket_, context); CAMLlocal1(block); #ifdef Socket_val SOCKET socket = Socket_val(socket_); From 40207b99f2b65cad5bea448fd42c406ea2e3ce92 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Fri, 12 Aug 2022 11:35:43 -0700 Subject: [PATCH 14/19] Set up Nix build, CI steps (#91) --- .github/workflows/build.yml | 22 +++++++++- flake.lock | 64 +++++++++++++++++++++++++++ flake.nix | 19 ++++++++ nix/ci/test.nix | 21 +++++++++ nix/default.nix | 27 ++++++++++++ nix/gh-actions.nix | 87 +++++++++++++++++++++++++++++++++++++ shell.nix | 28 ++++++++++++ tests/dune | 3 +- 8 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/ci/test.nix create mode 100644 nix/default.nix create mode 100644 nix/gh-actions.nix create mode 100644 shell.nix diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f4f1a1e..81402ab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,11 @@ name: Build -on: [push] +on: + pull_request: + branches: + - master + push: + branches: + - master jobs: build: runs-on: ${{ matrix.operating-system }} @@ -18,3 +24,17 @@ jobs: run: opam depext -yt mad - name: Build and test run: opam install -t . + nix-build: + runs-on: ubuntu-latest + strategy: + matrix: + ocamlVersion: [4_12, 4_13, 4_14, 5_00] + steps: + - uses: actions/checkout@v2 + - uses: cachix/install-nix-action@v17 + - uses: cachix/cachix-action@v10 + with: + name: anmonteiro + - name: "Run nix-build" + run: nix-build ./nix/ci/test.nix --argstr ocamlVersion ${{ matrix.ocamlVersion }} + diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..6d59edf --- /dev/null +++ b/flake.lock @@ -0,0 +1,64 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1660256260, + "narHash": "sha256-j3D3NzzPvw01cE/FNNXhId+YWSBB89PWXtgvOodrn4g=", + "owner": "anmonteiro", + "repo": "nix-overlays", + "rev": "6437d5b02eb5e836175baeb7178b3354e3b6d50b", + "type": "github" + }, + "original": { + "owner": "anmonteiro", + "repo": "nix-overlays", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1660165869, + "narHash": "sha256-nPPvvQTaWKOb/vHEcN/DD0eTmPsD4+UplD9H5mEp7Ak=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "08ca24c9f28a02c52ca0bc9ffe18c1b69bae2c59", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "08ca24c9f28a02c52ca0bc9ffe18c1b69bae2c59", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..88349b5 --- /dev/null +++ b/flake.nix @@ -0,0 +1,19 @@ +{ + description = "OCaml-SSL Nix Flake"; + + inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.nixpkgs.inputs.flake-utils.follows = "flake-utils"; + inputs.nixpkgs.url = "github:anmonteiro/nix-overlays"; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages."${system}"; + in + rec { + defaultPackage = pkgs.callPackage ./nix { }; + devShell = pkgs.callPackage ./shell.nix { + packages = [ defaultPackage ]; + }; + }); +} diff --git a/nix/ci/test.nix b/nix/ci/test.nix new file mode 100644 index 0000000..986deca --- /dev/null +++ b/nix/ci/test.nix @@ -0,0 +1,21 @@ +{ ocamlVersion }: + +let + lock = builtins.fromJSON (builtins.readFile ./../../flake.lock); + src = fetchGit { + url = with lock.nodes.nixpkgs.locked; "https://github.com/${owner}/${repo}"; + inherit (lock.nodes.nixpkgs.locked) rev; + # inherit (lock.nodes.nixpkgs.original) ref; + allRefs = true; + }; + + pkgs = import "${src}" { + extraOverlays = [ + (self: super: { + ocamlPackages = super.ocaml-ng."ocamlPackages_${ocamlVersion}"; + }) + ]; + }; + +in +pkgs.callPackage ./.. { doCheck = true; } diff --git a/nix/default.nix b/nix/default.nix new file mode 100644 index 0000000..6b932dc --- /dev/null +++ b/nix/default.nix @@ -0,0 +1,27 @@ +{ stdenv +, lib +, ocamlPackages +, openssl-oc +, doCheck ? false +, pkg-config +}: + +with ocamlPackages; + +buildDunePackage { + pname = "ssl"; + version = "n/a"; + + useDune2 = true; + + src = ../.; + + nativeBuildInputs = [ ocaml dune findlib pkg-config ]; + buildInputs = [ dune-configurator ]; + propagatedBuildInputs = [ + openssl-oc.dev + ]; + checkInputs = [ alcotest ]; + + inherit doCheck; +} diff --git a/nix/gh-actions.nix b/nix/gh-actions.nix new file mode 100644 index 0000000..f20d5e5 --- /dev/null +++ b/nix/gh-actions.nix @@ -0,0 +1,87 @@ +{ lib }: + +let + commonSteps = { name, signingKey }: [ + { + uses = "actions/checkout@v2"; + "with" = { + "submodules" = "recursive"; + }; + } + { + uses = "cachix/install-nix-action@v14.1"; + } + { + uses = "cachix/cachix-action@v10"; + "with" = { + inherit name signingKey; + }; + } + + ]; + + job = + { steps + , ocamlVersions ? [ + "4_12" + "4_13" + "4_14" + "5_00" + ] + , ... + }@attrs: (builtins.removeAttrs attrs [ "ocamlVersions" ]) // { + strategy = { + fail-fast = false; + matrix = { + ocamlVersion = ocamlVersions + ; + }; + }; + }; + + gh-actions = { + cachixBuild = { name, branches ? [ "master" ], os, cachix }: + lib.generators.toYAML { } { + inherit name; + on = { + pull_request = null; + push = { + inherit branches; + }; + }; + + jobs = lib.mapAttrs + (os: { run, name, ... }@conf: + job ({ + runs-on = os; + steps = commonSteps cachix + ++ [{ inherit name run; }]; + } // (if (conf ? ocamlVersions) then { + inherit (conf) ocamlVersions; + } else { }))) + os; + }; + }; + +in + +gh-actions.cachixBuild { + name = "Build"; + cachix = { + name = "anmonteiro"; + signingKey = "\${{ secrets.CACHIX_SIGNING_KEY }}"; + }; + os = { + macos-latest = { + name = "Run nix-build"; + ocamlVersions = [ "4_13" "4_14" "5_00" ]; + run = "nix-build ./nix/ci/test.nix -A native --argstr ocamlVersion \${{ matrix.ocamlVersion }}"; + }; + ubuntu-latest = { + ocamlVersions = [ "4_12" "4_13" "4_14" "5_00" ]; + name = "Run nix-build"; + run = "nix-build ./nix/ci/test.nix -A native -A musl64 --argstr ocamlVersion \${{ matrix.ocamlVersion }}"; + }; + }; + +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..86ce3ac --- /dev/null +++ b/shell.nix @@ -0,0 +1,28 @@ +{ packages +, lib +, mkShell +, release-mode ? false +, cacert +, curl +, ocamlPackages +, git +, opam +}: + +mkShell { + OCAMLRUNPARAM = "b"; + inputsFrom = packages; + buildInputs = + (with ocamlPackages; [ + merlin + ocamlformat + utop + alcotest + ]) ++ lib.optional release-mode [ + cacert + curl + ocamlPackages.dune-release + git + opam + ]; +} diff --git a/tests/dune b/tests/dune index 24e8687..0e74306 100644 --- a/tests/dune +++ b/tests/dune @@ -1,3 +1,4 @@ (test (name ssl_test) - (libraries ssl alcotest)) + (libraries ssl alcotest) + (deps digicert_certificate.pem)) From e630f27a371503caab927aed7d909a49746dcbb1 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Fri, 12 Aug 2022 11:44:39 -0700 Subject: [PATCH 15/19] Add release-mode shell --- flake.nix | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 88349b5..892a174 100644 --- a/flake.nix +++ b/flake.nix @@ -12,8 +12,15 @@ in rec { defaultPackage = pkgs.callPackage ./nix { }; - devShell = pkgs.callPackage ./shell.nix { - packages = [ defaultPackage ]; + devShells = { + default = pkgs.callPackage ./shell.nix { + packages = [ defaultPackage ]; + }; + + release = pkgs.callPackage ./shell.nix { + packages = [ defaultPackage ]; + release-mode = true; + }; }; }); } From 7564df0aa45d22d55dc62aa89a97fecb35742739 Mon Sep 17 00:00:00 2001 From: Firgeis Date: Wed, 17 Aug 2022 04:29:27 +0000 Subject: [PATCH 16/19] Use correct parameter for setup-ocaml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 81402ab..461c1a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v2 - uses: ocaml/setup-ocaml@v2 with: - ocaml-version: ${{ matrix.ocaml-version }} + ocaml-compiler: ${{ matrix.ocaml-version }} - name: Setup opam run: opam pin add -n . - name: Install dependencies From ab2c6b22053a570d10a92752f6c128afb84d5d24 Mon Sep 17 00:00:00 2001 From: Firgeis Date: Fri, 19 Aug 2022 04:30:31 +0000 Subject: [PATCH 17/19] Ensure openssl is installed --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 461c1a5..8f57473 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,6 +18,8 @@ jobs: - uses: ocaml/setup-ocaml@v2 with: ocaml-compiler: ${{ matrix.ocaml-version }} + - name: Ensure openssl + run: brew install openssl@3 - name: Setup opam run: opam pin add -n . - name: Install dependencies From 49cf625464516e2b0873c32fab964b71f0b57820 Mon Sep 17 00:00:00 2001 From: Firgeis Date: Sun, 21 Aug 2022 00:01:21 +0000 Subject: [PATCH 18/19] Run ensure only on macos --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f57473..09bc3f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,7 @@ jobs: with: ocaml-compiler: ${{ matrix.ocaml-version }} - name: Ensure openssl + if: runner.os == 'macOS' run: brew install openssl@3 - name: Setup opam run: opam pin add -n . From e844126314240e0b125a82c2439d71a6dbcca2c7 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Thu, 1 Sep 2022 16:06:46 -0700 Subject: [PATCH 19/19] Update CHANGES.md --- CHANGES.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 3131e3e..db8b93a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,9 @@ Unreleased ===== +0.5.12 (2022-08-12) +===== + - Add a few verification functions (#71): - `add_extra_chain_cert` to send additional chain certificates to the peer. - `add_cert_to_store`: to allow verification of the peer certificate CA. @@ -10,7 +13,7 @@ Unreleased - Fix a segmentation fault in the ALPN selection callback under OCaml 5 (#89). - Audit the C FFI and add `CAMLparamX` and `CAMLreturn` calls (#90). -0.5.11 +0.5.11 (2022-07-24) ===== - Add `digest` function (#65, #66).