Git Product home page Git Product logo

ocaml-ssl's Introduction

OCaml-SSL - OCaml bindings for the libssl

Copyright (c) 2003-2015 the Savonet Team.

LGPL license GitHub release Install with Opam ! Build Status

Installation

ocaml-ssl can be installed via OPAM:

opam install ssl

Is this library thread-safe?

Yes it is if and only if the first function you call in ocaml-ssl is Ssl_threads.init (and the second one should be Ssl.init).

Creating a self-signed ssl certificate

To get started quickly you can create a self-signed ssl certificate using openssl.

  1. First, create a 1024-bit private key to use when creating your CA.: openssl genrsa -des3 -out privkey.pem 1024
  2. Create a master certificate based on this key, to use when signing other certificates: openssl req -new -x509 -days 1001 -key privkey.pem -out cert.pem

SSL acknowledgment

This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit.

License

This library is released under the LGPL version 2.1 with the additional exemption that compiling, linking, and/or using OpenSSL is allowed.

As a special exception to the GNU Library General Public License, you may also link, statically or dynamically, a "work that uses the Library" with a publicly distributed version of the Library to produce an executable file containing portions of the Library, and distribute that executable file under terms of your choice, without any of the additional requirements listed in clause 6 of the GNU Library General Public License. By "a publicly distributed version of the Library", we mean either the unmodified Library, or a modified version of the Library that is distributed under the conditions defined in clause 3 of the GNU Library General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Library General Public License.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

The examples are under the GPL licence version 2.0.

ocaml-ssl's People

Contributors

anmonteiro avatar avsm avatar bobbypriam avatar calderonth avatar codeurimpulsif avatar craff avatar dra27 avatar drvink avatar edwintorok avatar firgeis avatar jcourreges avatar kit-ty-kate avatar lupus avatar mfp avatar misterda avatar nicolast avatar psafont avatar rgrinberg avatar schubev avatar smimram avatar tmcgilchrist avatar toots avatar vbmithr avatar vitoyucepi avatar vouillon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ocaml-ssl's Issues

Disable SSLv2

Hi,

SSLv2 support is (at least) disabled in the last Debian OpenSSL package, I guess it's related to DROWN... This prevented me from building Ocsigen from source using opam.

Would it be possible to add -DOPENSSL_NO_SSL3 to CFLAGS by default?

Thanks!

New release?

The change made in commit 8f698ba is now also required for Debian unstable, so it would be nice if it could make it into opam. Thanks.

ocaml-ssl won't link statically on FreeBSD

ocaml-ssl won't link statically on FreeBSD. Many link errors result, like:

/usr/local/lib/libssl.a(s3_srvr.o): In function ssl3_get_cert_verify': s3_srvr.c:(.text+0x1051): undefined reference to X509_certificate_type'
/usr/local/lib/libssl.a(s3_clnt.o): In function ssl_do_client_cert_cb': s3_clnt.c:(.text+0x91): undefined reference to ENGINE_load_ssl_client_cert'
/usr/local/lib/libssl.a(s3_clnt.o): In function ssl3_check_cert_and_algorithm': s3_clnt.c:(.text+0x465): undefined reference to X509_certificate_type'
/usr/local/lib/libssl.a(s3_enc.o): In function ssl3_change_cipher_state': s3_enc.c:(.text+0x1546): undefined reference to COMP_CTX_free'
s3_enc.c:(.text+0x155e): undefined reference to COMP_CTX_new' s3_enc.c:(.text+0x1612): undefined reference to COMP_CTX_free'
s3_enc.c:(.text+0x162a): undefined reference to `COMP_CTX_new'
...

Here's a demo program that demonstrates this:

let () = Ssl.init ()

Compile on FreeBSD with:

ocamlbuild -r -use-ocamlfind -pkgs ssl -lflags -ccopt,-static demo.native

The attached patch solves the problem, and works equally well with
dynamic linking.
patch.txt

Not compiling on Archlinux

[vb@nerenyi ~/code/ocaml-ssl]% ./configure                                                                 
configuring ocaml-ssl 0.4.7
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for pthread_create in -lpthread... yes
checking for ocamlc... /home/vb/.opam/4.01.0/bin/ocamlc
ocaml version is 4.01.0
ocaml library path is /home/vb/.opam/4.01.0/lib/ocaml
checking for ocamlopt... /home/vb/.opam/4.01.0/bin/ocamlopt
checking ocamlopt version... ok
checking for ocamlc.opt... /home/vb/.opam/4.01.0/bin/ocamlc.opt
checking ocamlc.opt version... ok
checking for ocamlopt.opt... /home/vb/.opam/4.01.0/bin/ocamlopt.opt
checking ocamlc.opt version... ok
checking for ocamldep... /home/vb/.opam/4.01.0/bin/ocamldep
checking for ocamllex... /home/vb/.opam/4.01.0/bin/ocamllex
checking for ocamlyacc... /home/vb/.opam/4.01.0/bin/ocamlyacc
checking for ocamldoc... /home/vb/.opam/4.01.0/bin/ocamldoc
checking for ocamlmktop... /home/vb/.opam/4.01.0/bin/ocamlmktop
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking for SSL_new in -lssl... no
configure: error: Cannot find libssl.
zsh: exit 1     ./configure

OpenSSL is installed. The configure script cannot understand that, dunno why yet.

Tagged versions including the configure script?

Hi,

To workaround the recent sourceforge outtage I changed the opam-repository to point to the github mirror, specifically the magic link which allows a tagged version to be downloaded as a .tar.gz. Unfortunately these tarballs don't contain the configure script so I added it directly to the opam-repository: have a look at [ocaml/opam-repository#4477]. This works but is obviously a bit ugly :)

It would be really nice if there could exist tarballs generated by github which contain the configure scripts i.e. if they were more similar to the official release tarballs. Assuming you want to keep the current meaning of the existing tags, perhaps this could be achieved by adding a parallel set of tags (e.g. release-x.y.z) which had the autogen stuff added? What do you think?

Thanks for writing these bindings btw! :)

Fatal error: exception Failure("Map.of_list_exn: duplicate key")

$ dune build
    discover src/c_flags.sexp,src/c_library_flags.sexp,src/ocaml_ssl.h (exit 2)
(cd _build/default/src && config/discover.exe)
which: pkg-config
-> found: /usr/bin/pkg-config
run: /usr/bin/pkg-config --print-errors openssl
-> process exited with code 0
-> stdout:
-> stderr:
run: /usr/bin/pkg-config --cflags openssl
-> process exited with code 0
-> stdout:
 | 
-> stderr:
run: /usr/bin/pkg-config --libs openssl
-> process exited with code 0
-> stdout:
 | -lssl -lcrypto 
-> stderr:
compiling c program:
 | #include <stdio.h>
 | #include <openssl/ssl.h>
 | 
 | 
 | #ifdef SSL_set_tlsext_host_name
 | const char *s0 = "BEGIN-0-true-END";
 | #else
 | const char *s0 = "BEGIN-0-false-END";
 | #endif
 | 
 | 
 | #ifdef SSL_EXT_TLS1_3_ONLY
 | const char *s1 = "BEGIN-1-true-END";
 | #else
 | const char *s1 = "BEGIN-1-false-END";
 | #endif
 | 
run: gcc -O2 -fno-strict-aliasing -fwrapv -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fPIC -I /usr/lib64/ocaml -o /tmp/ocaml-configuratorefa7ef/c-test-3/test.o -c /tmp/ocaml-configuratorefa7ef/c-test-3/test.c
-> process exited with code 0
-> stdout:
-> stderr:
Fatal error: exception Failure("Map.of_list_exn: duplicate key")

This is with the latest version from git and OCaml 4.11.0. It didn't happen with an earlier pre-release of 4.11.0, so I guess this is caused by some change in the Map module or compiler?

Compatibility with OCaml 4.04.0

In OPAM repository, the OCaml version must be under 4.04.0. Is there a reason? If not, could it be updated in OPAM?

Thanks.

OPAM Link for 0.5.6 release 404s

Hi,

Thanks for your great work on this library!

The 0.5.6 link on https://opam.ocaml.org/packages/ssl/ssl.0.5.6/ is broken -- it points to https://github.com/savonet/ocaml-ssl/archive/v0.5.6.tar.gz instead of https://github.com/savonet/ocaml-ssl/archive/0.5.6.zip. I think 0.5.6 was re-released along with 0.5.7 6 days ago, according to the release page, which changed the archive name to be consistent with the other releases.

I'm happy to submit the PR to opam-repository to update the link, but some applications may depend on the previous stable opam link. In particular, I was using a snapshot of the OPAM repository as part of my POPL'19 artifact submission (https://popl19.sigplan.org/track/POPL-2019-Artifact-Evaluation). If possible, could you please re-release v.0.5.6 using the previous URL, so it's consistent with OPAM?

Thanks for your time!

SSL-related error when building ocsigenserver on MacOS

I've submitted an issue to the ocsigenserver repo, but this seems to be related to SSL, so I'm posting here as well. The package ssl builds fine, but building ocsigenserver results in the following error:

#=== ERROR while compiling ocsigenserver.2.15.0 ===============================#
# context     2.0.5 | macos/x86_64 | ocaml-base-compiler.4.07.1 | https://opam.ocaml.org#6f498bfa
# path        ~/.opam/ocaml-base-compiler.4.07.1/.opam-switch/build/ocsigenserver.2.15.0
# command     ~/.opam/opam-init/hooks/sandbox.sh build make
# exit-code   2
# env-file    ~/.opam/log/ocsigenserver-76396-e7966f.env
# output-file ~/.opam/log/ocsigenserver-76396-e7966f.out
### output ###
# Undefined symbols for architecture x86_64:
# [...]
#   "_SSLv23_method", referenced from:
#       _ocaml_ssl_create_context in libssl_stubs.a(ssl_stubs.o)
#   "_SSLv23_server_method", referenced from:
#       _ocaml_ssl_create_context in libssl_stubs.a(ssl_stubs.o)
# ld: symbol(s) not found for architecture x86_64
# clang: error: linker command failed with exit code 1 (use -v to see invocation)
# File "caml_startup", line 1:
# Error: Error during linking
# make[2]: *** [ocsigenserver.opt] Error 2
# make[1]: *** [all] Error 2
# make: *** [all] Error 2

My system is MacOS 10.13.6.
Any suggestions?

Ssl.input_string fails with Ssl.Read_error exception

Ssl.input_string's implementation in ocaml-ssl-0.7.0 is broken, because Ssl.read (which is used in that implementation) never returns 0 (or a negative number) - instead it raises a Ssl.Read_error exception, with an Error_zero_return payload on end-of-file being reached. Any application of Ssl.input_string as currently appearing in ssl.ml will therefore end with an exception.

For what it is worth, here is a version which works for me:

let input_string sock =
  let bufsize = 2048 in
  let buf = Bytes.create bufsize in
  let rec loop acc =
    match Ssl.read sock buf 0 bufsize with
      num ->
       let text = Bytes.sub_string buf 0 num in
       loop (acc ^ text)
    | exception Ssl.Read_error err ->
       match err with Ssl.Error_zero_return -> acc
                    | _ -> raise (Ssl.Read_error err) in
  loop ""

Build Failure on OS X High Sierra

This package is an upstream dependency for Tezos and in the newest version of OS X, Apple has started LibreSSL from OpenSSL. Though OS X users can install OpenSSL via Homebrew, there does not appear to be a way to link it in. This issue details the problem and a few environment variables that can fix the issue.

Adding bindings for X509_digest

I wish to use ocaml-ssl as part of a piece of server software in which clients connect using client certificates. The server should be able to remember said certificates and it would be quite handy to be able to do that by just saving certificate fingerprints. Unfortunately there currently aren’t any bindings for the X509_digest function which would give me said fingerprint.

Would a pull-request be welcome? I am willing and able to submit one.

As per my use case I would add something along these lines:

(* See EVP_sha1, EVP_sha256 and EVP_sha384 *)
type evp = [`SHA1 | `SHA256 | `SHA384]

(* The string would contain binary data, as opposed to hex or base64. *)
val digest : evp -> certificate -> string

With non blocking socket some functions are a bit useless as it is.

It is not really because of Runtime_lock, but because of non blocking socket. All high level function provided by the Make functor
will only work if the retry exception are transformed into proper effect, or if the are placed inside a loop. A workaround is to provide an optional parameter which is an exception handler that could raise the desired effect.

Configure script should not silently fall back to arbitrary defaults when pkg-config fails

The configuration script uses arbitrary defaults when calling pkg-config fails:

https://github.com/savonet/ocaml-ssl/blob/0.5.9/src/config/discover.ml#L6

These defaults are wrong on some platforms.

What seems worse is that this fall-back is silent: one can successfully build this library and then get arcane linking failure when using it:

Undefined symbols for architecture x86_64:
  "_BIO_ctrl", referenced from:
      _ocaml_ssl_flush in libssl_stubs.a(ssl_stubs.o)
  "_BIO_free", referenced from:
      _ocaml_ssl_ctx_init_dh_from_file in libssl_stubs.a(ssl_stubs.o)
  "_BIO_new_file", referenced from:
      _ocaml_ssl_ctx_init_dh_from_file in libssl_stubs.a(ssl_stubs.o)
  "_DH_free", referenced from:
      _ocaml_ssl_ctx_init_dh_from_file in libssl_stubs.a(ssl_stubs.o)
  "_EC_KEY_free", referenced from:
      _ocaml_ssl_ctx_init_ec_from_named_curve in libssl_stubs.a(ssl_stubs.o)
  "_EC_KEY_new_by_curve_name", referenced from:
      _ocaml_ssl_ctx_init_ec_from_named_curve in libssl_stubs.a(ssl_stubs.o)
  "_ERR_clear_error", referenced from:
      _ocaml_ssl_write in libssl_stubs.a(ssl_stubs.o)
      _ocaml_ssl_write_bigarray in libssl_stubs.a(ssl_stubs.o)
      _ocaml_ssl_write_bigarray_blocking in libssl_stubs.a(ssl_stubs.o)
      _ocaml_ssl_read in libssl_stubs.a(ssl_stubs.o)
      _ocaml_ssl_read_into_bigarray in libssl_stubs.a(ssl_stubs.o)
      _ocaml_ssl_read_into_bigarray_blocking in libssl_stubs.a(ssl_stubs.o)
      _ocaml_ssl_accept in libssl_stubs.a(ssl_stubs.o)

Possible fix: require pkg-config.

Broken on OS X now, simple fix methinks

I think the new El Captain update changed the way /usr/local is done and it broke some bindings.

The current configure script errors would with

checking for openssl/ssl.h... no
configure: error: Cannot find libssl headers.

(Yes I have the headers installed) In my bindings the fix is to explicitly do something like -I/usr/local/include and -L/usr/local/lib for the compiler flags, not sure what the equivalent is for auto tools stack.

New release

I'd like to release a library that depends on some new, unreleased functionality (e.g. #57, #58 and #60).

May I gently request a release of ocaml-ssl, at your earliest convenience? Thanks!

Is there interest in a jbuilder port?

Hi,

It would be great to have this library built with jbuilder (correct installation of artifacts, windows support, easily part of other jbuilder projects, no non-ocaml dependencies). If you'd still like to maintain the parallel make based build system for your own use, that's fine too. But for opam, it would be really nice if ssl built with jbuilder. If there's interest, I can create a port fairly quickly.

fails to build on Mac with homebrew

$ opam depext ssl
# Detecting depexts using flags: x86_64 osx homebrew
# The following system packages are needed:
#  - openssl
#  - pkg-config
# All required OS packages found.
$ opam install ssl
The following actions will be performed:
  ∗  install ssl 0.5.3

=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  🐫 

=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  🐫 
[ERROR] The compilation of ssl failed at "sh -exc ./configure --prefix /Users/ashish/.opam/4.03.0 CPPFLAGS=\"$CPPFLAGS
        -I/opt/local/include -I/usr/local/opt/openssl/include\"".

#=== ERROR while compiling ssl.0.5.3 ==========================================#
# command      sh -exc ./configure --prefix /Users/ashish/.opam/4.03.0 CPPFLAGS="$CPPFLAGS -I/opt/local/include -I/usr/local/opt/openssl/include"
...
# checking for SSL_new in -lssl... no
# configure: error: Cannot find libssl.

When you do brew install openssl, it informs you that Apple has deprecated openssl, and so homebrew refuses to create symlinks within /usr/local. To use openssl, it suggests to add the flags -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib. So I noticed that the -I flag is handled by this project's opam file, but the -L flag isn't.

deperecated bindings

Hi, when trying to install ocsigenserver and eliom I stumpled upon a compilation error. According to Vasilis Papavasileiou (from the ocsigen mailing list) the error could be that the ocaml-ssl binding still refer to OpenSSL bindings deprecated in version 1.1. In fact, reverting the version of libssl to 1.0 fixed the issue.

The error reported when compiling ocsigenserver :

/home/colin/.opam/4.04.0/lib/ssl/libssl_threads_stubs.a(ssl_stubs.o): In 
function 'get_method':
 /home/colin/.opam/4.04.0/build/ssl.0.5.3/src/ssl_stubs.c:277: 
undefined reference to 'SSLv23_client_method'
/home/colin/.opam/4.04.0/build/ssl.0.5.3/src/ssl_stubs.c:281: 
undefined reference to 'SSLv23_server_method'
/home/colin/.opam/4.04.0/build/ssl.0.5.3/src/ssl_stubs.c:285: 
undefined reference to 'SSLv23_method'
collect2: error: ld returned 1 exit status
File "caml_startup", line 1:
Error: Error during linking
 make[2]: *** [ocsigenserver.opt] Error 2
 make[1]: *** [all] Error 2
 make: *** [all] Error 2

weird certificate issue on libera.chat

Hi, I've had issues connecting some IRC bots recently from ocaml-irc-client. Trying the stelnet example on it is interesting:

$ dune exec examples/stelnet.exe -- irc.libera.chat -p 6697
SSL connection ok.   
Certificate issuer:  /C=US/O=Let's Encrypt/CN=R3
subject: /CN=strontium.libera.chat
Cipher: TLS_AES_256_GCM_SHA384 (TLSv1.3)
TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD

Type 'exit' to quit.

:strontium.libera.chat NOTICE * :*** Checking Ident
:strontium.libera.chat NOTICE * :*** Looking up your hostname...

but with paranoid:

$ dune exec examples/stelnet.exe -- irc.libera.chat -p 6697 -w
Certificate[2] subject=/C=US/O=Internet Security Research Group/CN=ISRG Root X1
Certificate[2] issuer =/O=Digital Signature Trust Co./CN=DST Root CA X3
SSL: rejecting connection - error=20
Fatal error: exception SSL connection() error: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed

SSL with select

Hi,

I'm using SSL for reading data from various remote services over secure websockets. The scheme is following: I create the socket, embed it in the SSL context and add the socket to the reading list for Unix.select. When the socket fires, I use Ssl.read to get the data.

Everything is working well except with the one service where I get Ssl.Read_error.Error_syscall: error:00000000:lib(0):func(0):reason(0) after receiving each websocket frame (size ~5-6Kb). By the way, frames here are much bigger than on other services, but I'm not sure it's the reason.

I ignore syscall errors because frames continue to arrive. Then, always after one minute I get Ssl.Read_error.Error_zero_return: error:00000000:lib(0):func(0):reason(0), which means the peer closed SSL socket for writing and I have to restart the process because no new data will be received from this socket.

Problem is perfectly reproducible. At the same time examples for this service and my own test implementation with Node.JS receive the data for hours without any problems.

I assume I do something wrong or setup socket/SSL too straightforward(see below).

Any help or ideas would be strongly appreciated.

  let sock = Unix.socket PF_INET SOCK_STREAM 0 in
  let laddr = Unix.inet_addr_of_string p.interface in
  Unix.bind sock (ADDR_INET (laddr,0));
  Unix.connect sock addr;
  let (sock, res) =
    let req = Bytes.of_string http_request in
    if ssl then begin
      Ssl.init ();
      let ctx = create_context TLSv1_2 Client_context in
      let sock = Ssl.embed_socket sock ctx in
      Ssl.connect sock;
      (SslSock sock, (write sock req 0 http_request_len))
    end else
      (UnixSock sock, (Unix.write sock req 0 http_request_len))

dune runtest gives an error in ssl_error test

File "tests/dune", line 13, characters 7-15:
13 |  (name ssl_comm)
            ^^^^^^^^
Testing `Ssl communication'.
This run has ID `WYHZXY0C'.

  [OK]          Communication          0   Test init.
> [FAIL]        Communication          1   Test error queue.

┌──────────────────────────────────────────────────────────────────────────────┐
│ [FAIL]        Communication          1   Test error queue.                   │
└──────────────────────────────────────────────────────────────────────────────┘
ASSERT Error code
File "tests/ssl_comm.ml", line 12, character 4:
FAIL Error code

   Expected: `268959746'
   Received: `537346050'

SSL: Method error with 0.5.6

Could be related to the switch to dune?

Minimal repro:

FROM ocaml/opam2:alpine-3.7-ocaml-4.06

RUN opam repo set-url default https://opam.ocaml.org && opam update
RUN sudo apk add --no-cache m4 pkgconf libressl-dev
RUN opam install ssl=0.5.6 cohttp-lwt-unix lwt_ssl
$ docker build . -t ssl-repro
...
$ docker run -it --rm ssl-repro cohttp-curl-lwt https://reddit.com
cohttp-curl: internal error, uncaught exception:
             SSL: Method error

Also reproducible on my OSX machine.

Ssl.disable_protocols disables too many

For a client context created with all protocols permitted, if I try to disable just SSLv23 and TLSv1_1, then I find it cannot make a connection to a server that accepts only TLSv1_2.

Here's the essence of the change I made (in a program using the Ssl module) to work around the problem:
thomassa/xapi-xe@1dc8494?diff=unified

   let ctx =
     (* Here SSLv23 means ALL protocols *)
     Ssl.create_context
       Ssl.SSLv23
       Ssl.Client_context
   in
-  (* Disable SSL v2 and v3, and TLSv1.1, leaving only TLSv1.0 and TLSv1.2 *)
-  Ssl.disable_protocols ctx [Ssl.SSLv23; Ssl.TLSv1_1];
+  (* Disable SSL v2 and v3, leaving only TLSv1.0 and TLSv1.1 and TLSv1.2 *)
+  (* We don't need 1.1, but if we add it to the list then 1.2 gets disabled
+   * too: a bug in the Ssl module v0.5.2 (or the libssl it is using) *)
+  Ssl.disable_protocols ctx [Ssl.SSLv23];

This is on Ubuntu with openssl package version 1.0.1f-1ubuntu2.15

Ocaml 4 win32 MSVC bugs

Got those errors:

ssl_stubs.c
ssl_stubs.c(579) : error C2275: value: недопустимое использование этого типа в качестве выражения
        c:\ocamlms\lib\caml\mlvalues.h(60): см. объявление "value"
ssl_stubs.c(579) : error C2146: синтаксическая ошибка: отсутствие ";" перед идентификатором "block"
ssl_stubs.c(579) : error C2065: block: необъявленный идентификатор
ssl_stubs.c(579) : error C2143: синтаксическая ошибка: отсутствие ";" перед "тип"
ssl_stubs.c(579) : error C2143: синтаксическая ошибка: отсутствие ";" перед "тип"
ssl_stubs.c(580) : error C2065: block: необъявленный идентификатор
ssl_stubs.c(581) : error C2065: block: необъявленный идентификатор
ssl_stubs.c(582) : error C2065: block: необъявленный идентификатор
ssl_stubs.c(585) : error C2061: синтаксическая ошибка: идентификатор "ocaml_ssl_get_issuer"
ssl_stubs.c(585) : error C2059: синтаксическая ошибка: ;
ssl_stubs.c(585) : error C2059: синтаксическая ошибка: тип
ssl_stubs.c(604) : error C2143: синтаксическая ошибка: отсутствие ";" перед "тип"
ssl_stubs.c(606) : error C2065: subject: необъявленный идентификатор
ssl_stubs.c(606) : warning C4047: ==: "int" отличается по уровням косвенного обращения от "void *"
ssl_stubs.c(608) : error C2065: subject: необъявленный идентификатор
ssl_stubs.c(608) : warning C4047: функция: "const char *" отличается по уровням косвенного обращения от "int"
ssl_stubs.c(608) : warning C4024: caml_copy_string: различные типы для формального и фактического параметров 1
ssl_stubs.c(611) : error C2061: синтаксическая ошибка: идентификатор "ocaml_ssl_ctx_load_verify_locations"
ssl_stubs.c(611) : error C2059: синтаксическая ошибка: ;
ssl_stubs.c(611) : error C2059: синтаксическая ошибка: тип

While compiling this:

#include <string.h>
#include <assert.h>
#include <C:\ocamlms\lib\caml/alloc.h>
#include <C:\ocamlms\lib\caml/callback.h>
#include <C:\ocamlms\lib\caml/custom.h>
#include <C:\ocamlms\lib\caml/fail.h>
#include <C:\ocamlms\lib\caml/memory.h>
#include <C:\ocamlms\lib\caml/mlvalues.h>
#include <C:\ocamlms\lib\caml/signals.h>
#include <C:\ocamlms\lib\caml/unixsupport.h>
#include <C:\OpenSSL-Win32\include\openssl/ssl.h>
#include <C:\OpenSSL-Win32\include\openssl/pem.h>
#include <C:\OpenSSL-Win32\include\openssl/err.h>
#include <C:\OpenSSL-Win32\include\openssl/crypto.h>
#include <windows.h>

static int client_verify_callback(int, X509_STORE_CTX *);

/*******************
 * Data structures *
 *******************/

/* Contexts */

#define Ctx_val(v) (*((SSL_CTX**)Data_custom_val(v)))

static void finalize_ctx(value block)
{
  SSL_CTX *ctx = Ctx_val(block);
  SSL_CTX_free(ctx);
}

static struct custom_operations ctx_ops =
{
  "ocaml_ssl_ctx",
  finalize_ctx,
  custom_compare_default,
  custom_hash_default,
  custom_serialize_default,
  custom_deserialize_default
};

/* Sockets */

#define SSL_val(v) (*((SSL**)Data_custom_val(v)))

static void finalize_ssl_socket(value block)
{
  SSL *ssl = SSL_val(block);
  SSL_free(ssl);
}

static struct custom_operations socket_ops =
{
  "ocaml_ssl_socket",
  finalize_ssl_socket,
  custom_compare_default,
  custom_hash_default,
  custom_serialize_default,
  custom_deserialize_default
};


/******************
 * Initialization *
 ******************/


struct CRYPTO_dynlock_value
{
  HANDLE mutex;
};

static HANDLE *mutex_buf = NULL;

static void locking_function(int mode, int n, const char *file, int line)
{
  if (mode & CRYPTO_LOCK)
    WaitForSingleObject(mutex_buf[n], INFINITE);
  else
    ReleaseMutex(mutex_buf[n]);
}

static struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line)
{
  struct CRYPTO_dynlock_value *value;

  value = malloc(sizeof(struct CRYPTO_dynlock_value));
  if (!value)
    return NULL;
  if (!(value->mutex = CreateMutex(NULL, FALSE, NULL)))
    {
      free(value);
      return NULL;
    }

  return value;
}

static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)
{
  if (mode & CRYPTO_LOCK)
    WaitForSingleObject(l->mutex, INFINITE);
  else
    ReleaseMutex(l->mutex);
}

//static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line)
//{
//  CloseHandle(l->mutex);
//  free(l);
//};
//struct CRYPTO_dynlock_value
//{
//  pthread_mutex_t mutex;
//};

//static pthread_mutex_t *mutex_buf = NULL;


static unsigned long id_function(void)
{
  return ((unsigned long) pthread_self());
}




static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line)
{
  pthread_mutex_destroy(&l->mutex);
  free(l);
}

CAMLprim value ocaml_ssl_init(value use_threads)
{
  int i;

  SSL_library_init();
  SSL_load_error_strings();

  if(Int_val(use_threads))
  {
    mutex_buf = malloc(CRYPTO_num_locks() * sizeof(HANDLE));
    assert(mutex_buf);
    for (i = 0; i < CRYPTO_num_locks(); i++)
      mutex_buf[i] = CreateMutex(NULL, FALSE, NULL);
    CRYPTO_set_locking_callback(locking_function);
    CRYPTO_set_dynlock_create_callback(dyn_create_function);
    CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
    CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
  }

  return Val_unit;
}

CAMLprim value ocaml_ssl_get_error_string(value unit)
{
  char buf[256];
  ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
  return caml_copy_string(buf);
}


/*****************************
 * Context-related functions *
 *****************************/

static const SSL_METHOD *get_method(int protocol, int type)
{
  const SSL_METHOD *method = NULL;

  caml_enter_blocking_section();
  switch (protocol)
  {
    case 0:
      switch (type)
      {
        case 0:
          method = SSLv23_client_method();
          break;

        case 1:
          method = SSLv23_server_method();
          break;

        case 2:
          method = SSLv23_method();
          break;
      }
      break;

    case 1:
      switch (type)
      {
        case 0:
          method = SSLv3_client_method();
          break;

        case 1:
          method = SSLv3_server_method();
          break;

        case 2:
          method = SSLv3_method();
          break;
      }
      break;

    case 2:
      switch (type)
      {
        case 0:
          method = TLSv1_client_method();
          break;

        case 1:
          method = TLSv1_server_method();
          break;

        case 2:
          method = TLSv1_method();
          break;
      }
      break;

    default:
      caml_leave_blocking_section();
      caml_invalid_argument("Unknown method (this should not have happened, please report).");
      break;
  }
  caml_leave_blocking_section();

  if (method == NULL)
    caml_raise_constant(*caml_named_value("ssl_exn_method_error"));

  return method;
}

CAMLprim value ocaml_ssl_create_context(value protocol, value type)
{
  value block;
  SSL_CTX *ctx;
  const SSL_METHOD *method = get_method(Int_val(protocol), Int_val(type));

  caml_enter_blocking_section();
  ctx = SSL_CTX_new(method);
  if (!ctx)
  {
    caml_leave_blocking_section();
    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();

  block = caml_alloc_custom(&ctx_ops, sizeof(SSL_CTX*), 0, 1);
  Ctx_val(block) = ctx;
  return block;
}

CAMLprim value ocaml_ssl_ctx_use_certificate(value context, value cert, value privkey)
{
  CAMLparam3(context, cert, privkey);
  SSL_CTX *ctx = Ctx_val(context);
  char *cert_name = String_val(cert);
  char *privkey_name = String_val(privkey);

  caml_enter_blocking_section();
  if (SSL_CTX_use_certificate_chain_file(ctx, cert_name) <= 0)
  {
    caml_leave_blocking_section();
    caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
  }
  if (SSL_CTX_use_PrivateKey_file(ctx, privkey_name, SSL_FILETYPE_PEM) <= 0)
  {
    caml_leave_blocking_section();
    caml_raise_constant(*caml_named_value("ssl_exn_private_key_error"));
  }
  if (!SSL_CTX_check_private_key(ctx))
  {
    caml_leave_blocking_section();
    caml_raise_constant(*caml_named_value("ssl_exn_unmatching_keys"));
  }
  caml_leave_blocking_section();

  CAMLreturn(Val_unit);
}

CAMLprim value ocaml_ssl_get_verify_result(value socket)
{
  CAMLparam1(socket);
  int ans;
  SSL *ssl = SSL_val(socket);

  caml_enter_blocking_section();
  ans = SSL_get_verify_result(ssl);
  caml_leave_blocking_section();

  CAMLreturn(Val_int(ans));
}

CAMLprim value ocaml_ssl_get_client_verify_callback_ptr(value unit)
{
  return (value)client_verify_callback;
}

CAMLprim value ocaml_ssl_ctx_set_verify(value context, value vmode, value vcallback)
{
  CAMLparam3(context, vmode, vcallback);
  SSL_CTX *ctx = Ctx_val(context);
  int mode = 0;
  value mode_tl = vmode;
  int (*callback) (int, X509_STORE_CTX*) = NULL;

  if (Is_long(vmode))
    mode = SSL_VERIFY_NONE;

  while (Is_block(mode_tl))
  {
    switch(Int_val(Field(mode_tl, 0)))
    {
      case 0:
        mode |= SSL_VERIFY_PEER;
        break;

      case 1:
        mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_PEER;
        break;

      case 2:
        mode |= SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_PEER;
        break;

      default:
        caml_invalid_argument("mode");
    }

    mode_tl = Field(mode_tl, 1);
  }

  if (Is_block(vcallback))
    callback = (int(*) (int, X509_STORE_CTX*))Field(vcallback, 0);

  caml_enter_blocking_section();
  SSL_CTX_set_verify(ctx, mode, callback);
  caml_leave_blocking_section();

  CAMLreturn(Val_unit);
}

CAMLprim value ocaml_ssl_ctx_set_verify_depth(value context, value vdepth)
{
  SSL_CTX *ctx = Ctx_val(context);
  int depth = Int_val(vdepth);

  if (depth < 0)
    caml_invalid_argument("depth");

  caml_enter_blocking_section();
  SSL_CTX_set_verify_depth(ctx, depth);
  caml_leave_blocking_section();

  return Val_unit;
}

CAMLprim value ocaml_ssl_ctx_set_client_CA_list_from_file(value context, value vfilename)
{
  CAMLparam2(context, vfilename);
  SSL_CTX *ctx = Ctx_val(context);
  char *filename = String_val(vfilename);
  STACK_OF(X509_NAME) *cert_names;

  caml_enter_blocking_section();
  cert_names = SSL_load_client_CA_file(filename);
  if (cert_names != 0)
    SSL_CTX_set_client_CA_list(ctx, cert_names);
  else
  {
    caml_leave_blocking_section();
    caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
  }
  caml_leave_blocking_section();

  CAMLreturn(Val_unit);
}

static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata)
{
  value s;
  int len;

  caml_leave_blocking_section();
  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();

  return len;
}

CAMLprim value ocaml_ssl_ctx_set_default_passwd_cb(value context, value cb)
{
  CAMLparam2(context, cb);
  SSL_CTX *ctx = Ctx_val(context);
  value *pcb;

  /* TODO: this never gets freed or even unregistered */
  pcb = malloc(sizeof(value));
  *pcb = cb;
  caml_register_global_root(pcb);

  caml_enter_blocking_section();
  SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
  SSL_CTX_set_default_passwd_cb_userdata(ctx, pcb);
  caml_leave_blocking_section();

  CAMLreturn(Val_unit);
}

/****************************
 * Cipher-related functions *
 ****************************/

CAMLprim value ocaml_ssl_ctx_set_cipher_list(value context, value ciphers_string)
{
  CAMLparam2(context, ciphers_string);
  SSL_CTX *ctx = Ctx_val(context);
  char *ciphers = String_val(ciphers_string);

  if(*ciphers == 0)
    caml_raise_constant(*caml_named_value("ssl_exn_cipher_error"));

  caml_enter_blocking_section();
  if(SSL_CTX_set_cipher_list(ctx, ciphers) != 1)
  {
    caml_leave_blocking_section();
    caml_raise_constant(*caml_named_value("ssl_exn_cipher_error"));
  }
  caml_leave_blocking_section();

  CAMLreturn(Val_unit);
}
SSL_CIPHER *cipher;
CAMLprim value ocaml_ssl_get_current_cipher(value socket)
{
  CAMLparam1(socket);
  SSL *ssl = SSL_val(socket);
  caml_enter_blocking_section();
  cipher = (SSL_CIPHER*)SSL_get_current_cipher(ssl);
  caml_leave_blocking_section();
  if (!cipher)
    caml_raise_constant(*caml_named_value("ssl_exn_cipher_error"));

  CAMLreturn((value)cipher);
}

CAMLprim value ocaml_ssl_get_cipher_description(value vcipher)
{
  char buf[1024];
  SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher;

  caml_enter_blocking_section();
  SSL_CIPHER_description(cipher, buf, 1024);
  caml_leave_blocking_section();

  return caml_copy_string(buf);
}

CAMLprim value ocaml_ssl_get_cipher_name(value vcipher)
{
  const char *name;
  SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher;

  caml_enter_blocking_section();
  name = SSL_CIPHER_get_name(cipher);
  caml_leave_blocking_section();

  return caml_copy_string(name);
}

CAMLprim value ocaml_ssl_get_cipher_version(value vcipher)
{
  char *version;
  SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher;

  caml_enter_blocking_section();
  version = SSL_CIPHER_get_version(cipher);
  caml_leave_blocking_section();

  return caml_copy_string(version);
}

/*********************************
 * Certificate-related functions *
 *********************************/

#define Cert_val(v) (*((X509**)Data_custom_val(v)))

static void finalize_cert(value block)
{
  X509 *cert = Cert_val(block);
  X509_free(cert);
}

static struct custom_operations cert_ops =
{
  "ocaml_ssl_cert",
  finalize_cert,
  custom_compare_default,
  custom_hash_default,
  custom_serialize_default,
  custom_deserialize_default
};

CAMLprim value ocaml_ssl_read_certificate(value vfilename)
{
  value block;
  char *filename = String_val(vfilename);
  X509 *cert = NULL;
  FILE *fh = NULL;

  if((fh = fopen(filename, "r")) == NULL)
    caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));

  caml_enter_blocking_section();
  if((PEM_read_X509(fh, &cert, 0, 0)) == NULL)
  {
    fclose(fh);
    caml_leave_blocking_section();
    caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
  }
  fclose(fh);
  caml_leave_blocking_section();

  block = caml_alloc_custom(&cert_ops, sizeof(X509*), 0, 1);
  Cert_val(block) = cert;
  return block;
}

CAMLprim value ocaml_ssl_write_certificate(value vfilename, value certificate)
{
  CAMLparam2(vfilename, certificate);
  char *filename = String_val(vfilename);
  X509 *cert = Cert_val(certificate);
  FILE *fh = NULL;

  if((fh = fopen(filename, "w")) == NULL)
    caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));

  caml_enter_blocking_section();
  if(PEM_write_X509(fh, cert) == 0)
  {
    fclose(fh);
    caml_leave_blocking_section();
    caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
  }
  fclose(fh);
  caml_leave_blocking_section();

  CAMLreturn(Val_unit);
}
X509 *cert;

CAMLprim value ocaml_ssl_get_certificate(value socket)
{
  CAMLparam1(socket);
  SSL *ssl = SSL_val(socket);

  caml_enter_blocking_section();
  cert = SSL_get_peer_certificate(ssl);
  caml_leave_blocking_section();

  if (!cert)
    caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));

  CAMLlocal1(block);
  block = caml_alloc_final(2, finalize_cert, 0, 1);
  (*((X509 **) Data_custom_val(block))) = cert;
  CAMLreturn(block);
}

CAMLprim value ocaml_ssl_get_issuer(value certificate)
{
  CAMLparam1(certificate);
  X509 *cert = Cert_val(certificate);

  caml_enter_blocking_section();
  char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
  caml_leave_blocking_section();
  if (!issuer) caml_raise_not_found ();

  CAMLreturn(caml_copy_string(issuer));
}

CAMLprim value ocaml_ssl_get_subject(value certificate)
{
  CAMLparam1(certificate);
  X509 *cert = Cert_val(certificate);

  caml_enter_blocking_section();
  char *subject = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
  caml_leave_blocking_section();
  if (subject == NULL) caml_raise_not_found ();

  CAMLreturn(caml_copy_string(subject));
}

CAMLprim value ocaml_ssl_ctx_load_verify_locations(value context, value ca_file, value ca_path)
{
  CAMLparam3(context, ca_file, ca_path);
  SSL_CTX *ctx = Ctx_val(context);
  char *CAfile = String_val(ca_file);
  char *CApath = String_val(ca_path);

  if(*CAfile == 0)
    CAfile = NULL;
  if(*CApath == 0)
    CApath = NULL;

  caml_enter_blocking_section();
  if(SSL_CTX_load_verify_locations(ctx, CAfile, CApath) != 1)
  {
    caml_leave_blocking_section();
    caml_invalid_argument("cafile or capath");
  }
  caml_leave_blocking_section();

  CAMLreturn(Val_unit);
}

/*************************
 * Operations on sockets *
 *************************/

CAMLprim value ocaml_ssl_get_file_descr(value socket)
{
  CAMLparam1(socket);
  SSL *ssl = SSL_val(socket);
  int fd;

  caml_enter_blocking_section();
  fd = SSL_get_fd(ssl);
  caml_leave_blocking_section();

  CAMLreturn(Val_int(fd));
}

CAMLprim value ocaml_ssl_embed_socket(value socket_, value context)
{
  CAMLparam1(context);
  CAMLlocal1(block);
  SOCKET socket = Socket_val(socket_);
  SSL_CTX *ctx = Ctx_val(context);
  SSL *ssl;

  block = caml_alloc_custom(&socket_ops, sizeof(SSL*), 0, 1);

  if (socket < 0)
    caml_raise_constant(*caml_named_value("ssl_exn_invalid_socket"));
  caml_enter_blocking_section();
  ssl = SSL_new(ctx);
  if (!ssl)
  {
    caml_leave_blocking_section();
    caml_raise_constant(*caml_named_value("ssl_exn_handler_error"));
  }
  SSL_set_fd(ssl, socket);
  caml_leave_blocking_section();
  SSL_val(block) = ssl;

  CAMLreturn(block);
}

CAMLprim value ocaml_ssl_connect(value socket)
{
  CAMLparam1(socket);
  int ret, err;
  SSL *ssl = SSL_val(socket);

  caml_enter_blocking_section();
  ret = SSL_connect(ssl);
  err = SSL_get_error(ssl, ret);
  caml_leave_blocking_section();
  if (err != SSL_ERROR_NONE)
    caml_raise_with_arg(*caml_named_value("ssl_exn_connection_error"), Val_int(err));

  CAMLreturn(Val_unit);
}

CAMLprim value ocaml_ssl_verify(value socket)
{
  CAMLparam1(socket);
  SSL *ssl = SSL_val(socket);
  long ans;

  caml_enter_blocking_section();
  ans = SSL_get_verify_result(ssl);
  caml_leave_blocking_section();

  if (ans != 0)
  {
    if (2 <= ans && ans <= 32)
      caml_raise_with_arg(*caml_named_value("ssl_exn_verify_error"), Val_int(ans - 2)); /* Not very nice, but simple */
    else
      caml_raise_with_arg(*caml_named_value("ssl_exn_verify_error"), Val_int(31));
  }

  CAMLreturn(Val_unit);
}

CAMLprim value ocaml_ssl_write(value socket, value buffer, value start, value length)
{
  CAMLparam2(socket, buffer);
  int ret, err;
  int buflen = Int_val(length);
  char *buf = malloc(buflen);
  SSL *ssl = SSL_val(socket);

  if (Int_val(start) + Int_val(length) > caml_string_length(buffer))
    caml_invalid_argument("Buffer too short.");

  memmove(buf, (char*)String_val(buffer) + Int_val(start), buflen);
  caml_enter_blocking_section();
  ERR_clear_error();
  ret = SSL_write(ssl, buf, buflen);
  err = SSL_get_error(ssl, ret);
  caml_leave_blocking_section();
  free(buf);

  if (err != SSL_ERROR_NONE)
    caml_raise_with_arg(*caml_named_value("ssl_exn_write_error"), Val_int(err));

  CAMLreturn(Val_int(ret));
}

CAMLprim value ocaml_ssl_read(value socket, value buffer, value start, value length)
{
  CAMLparam2(socket, buffer);
  int ret, err;
  int buflen = Int_val(length);
  char *buf = malloc(buflen);
  SSL *ssl = SSL_val(socket);

  if (Int_val(start) + Int_val(length) > caml_string_length(buffer))
    caml_invalid_argument("Buffer too short.");

  caml_enter_blocking_section();
  ERR_clear_error();
  ret = SSL_read(ssl, buf, buflen);
  err = SSL_get_error(ssl, ret);
  caml_leave_blocking_section();
  memmove(((char*)String_val(buffer)) + Int_val(start), buf, buflen);
  free(buf);

  if (err != SSL_ERROR_NONE)
    caml_raise_with_arg(*caml_named_value("ssl_exn_read_error"), Val_int(err));

  CAMLreturn(Val_int(ret));
}

CAMLprim value ocaml_ssl_accept(value socket)
{
  CAMLparam1(socket);
  SSL *ssl = SSL_val(socket);

  int ret, err;
  caml_enter_blocking_section();
  ERR_clear_error();
  ret = SSL_accept(ssl);
  err = SSL_get_error(ssl, ret);
  caml_leave_blocking_section();
  if (err != SSL_ERROR_NONE)
    caml_raise_with_arg(*caml_named_value("ssl_exn_accept_error"), Val_int(err));
  caml_leave_blocking_section();

  CAMLreturn(Val_unit);
}

CAMLprim value ocaml_ssl_flush(value socket)
{
  CAMLparam1(socket);
  SSL *ssl = SSL_val(socket);
  BIO *bio;

  caml_enter_blocking_section();
  bio = SSL_get_wbio(ssl);
  if(bio)
  {
    /* TODO: raise an error */
    assert(BIO_flush(bio) == 1);
  }
  caml_leave_blocking_section();

  CAMLreturn(Val_unit);
}

CAMLprim value ocaml_ssl_shutdown(value socket)
{
  CAMLparam1(socket);
  SSL *ssl = SSL_val(socket);
  int ret;

  caml_enter_blocking_section();
  ret = SSL_shutdown(ssl);
  if (!ret)
    SSL_shutdown(ssl);
  caml_leave_blocking_section();
  /* close(SSL_get_fd(SSL_val(socket))); */

  CAMLreturn(Val_unit);
}

/* ======================================================== */
/*
   T.F.:
   Here, we steal the client_verify_callback function from
   netkit-telnet-ssl-0.17.24+0.1/libtelnet/ssl.c

   From the original file header:

   The modifications to support SSLeay were done by Tim Hudson
   [email protected]

   You can do whatever you like with these patches except pretend that
   you wrote them.

   Email [email protected] to get instructions on how to
   join the mailing list that discusses SSLeay and also these patches.
   */

#define ONELINE_NAME(X) X509_NAME_oneline(X, 0, 0)

/* Quick translation ... */
#ifndef VERIFY_ERR_UNABLE_TO_GET_ISSUER
#define VERIFY_ERR_UNABLE_TO_GET_ISSUER X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
#endif
#ifndef VERIFY_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
#define VERIFY_ERR_DEPTH_ZERO_SELF_SIGNED_CERT X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
#endif
#ifndef VERIFY_OK
#define VERIFY_OK X509_V_OK
#endif
#ifndef VERIFY_ERR_UNABLE_TO_GET_ISSUER
#define VERIFY_ERR_UNABLE_TO_GET_ISSUER X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
#endif

/* Need to think about this mapping in terms of what the real
 * equivalent of this actually is.
 */
#ifndef VERIFY_ROOT_OK
#define VERIFY_ROOT_OK VERIFY_OK
#endif


static int client_verify_callback(int ok, X509_STORE_CTX *ctx)
{
  char *subject, *issuer;
  int depth, error;
  char *xs;

  depth = ctx->error_depth;
  error = ctx->error;
  xs = (char *)X509_STORE_CTX_get_current_cert(ctx);

  subject = issuer = NULL;

  /* First thing is to have a meaningful name for the current
   * certificate that is being verified ... and if we cannot
   * determine that then something is seriously wrong!
   */
  subject=(char*)ONELINE_NAME(X509_get_subject_name((X509*)xs));
  if (subject == NULL)
  {
    ERR_print_errors_fp(stderr);
    ok = 0;
    goto return_time;
  }
  issuer = (char*)ONELINE_NAME(X509_get_issuer_name((X509*)xs));
  if (issuer == NULL)
  {
    ERR_print_errors_fp(stderr);
    ok = 0;
    goto return_time;
  }

  /* If the user wants us to be chatty about things then this
   * is a good time to wizz the certificate chain past quickly :-)
   */
  if (1)
  {
    fprintf(stderr, "Certificate[%d] subject=%s\n", depth, subject);
    fprintf(stderr, "Certificate[%d] issuer =%s\n", depth, issuer);
    fflush(stderr);
  }

  /* If the server is using a self signed certificate then
   * we need to decide if that is good enough for us to
   * accept ...
   */
  if (error == VERIFY_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
  {
    if (1)
    {
      /* Make 100% sure that in secure more we drop the
       * connection if the server does not have a
       * real certificate!
       */
      fprintf(stderr,"SSL: rejecting connection - server has a self-signed certificate\n");
      fflush(stderr);

      /* Sometimes it is really handy to be able to debug things
       * and still get a connection!
       */
      ok = 0;
      goto return_time;
    }
    else
    {
      ok = 1;
      goto return_time;
    }
  }

  /* If we have any form of error in secure mode we reject the connection. */
  if (!((error == VERIFY_OK) || (error == VERIFY_ROOT_OK)))
  {
    if (1)
    {
      fprintf(stderr, "SSL: rejecting connection - error=%d\n", error);
      if (error == VERIFY_ERR_UNABLE_TO_GET_ISSUER)
      {
        fprintf(stderr, "unknown issuer: %s\n", issuer);
      }
      else
      {
        ERR_print_errors_fp(stderr);
      }
      fflush(stderr);
      ok = 0;
      goto return_time;
    }
    else
    {
      /* Be nice and display a lot more meaningful stuff
       * so that we know which issuer is unknown no matter
       * what the callers options are ...
       */
      if (error == VERIFY_ERR_UNABLE_TO_GET_ISSUER)
      {
        fprintf(stderr, "SSL: unknown issuer: %s\n", issuer);
        fflush(stderr);
      }
    }
  }

return_time:

  /* Clean up things. */
  if (subject)
    free(subject);
  if (issuer)
    free(issuer);

  return ok;
}

Any ideas how to resolve those bugs?

Ivan

`<openssl/ssl.h>` No such file or directory on 4.12+options opam switch with `ocaml-option-static`

I'm trying to install ssl on a musl static switch on ubuntu 20.04

$ sudo apt install musl-tools libssl-dev
$ opam info ocaml-option-static
$ mkdir testthis
$ cd testthis
$ opam switch create . --packages=ocaml-variants.4.12.0+options,ocaml-option-static
$ opam install conf-libssl
$ opam install ssl
...etc...
...etc...
#=== ERROR while compiling ssl.0.5.10 =========================================#
# context     2.1.0 | linux/x86_64 | ocaml-option-static.1 ocaml-variants.4.12.0+options | https://opam.ocaml.org#88233ad0
# path        ~/testthis/_opam/.opam-switch/build/ssl.0.5.10
# command     ~/.opam/opam-init/hooks/sandbox.sh build dune build -p ssl -j 7                                                                                         
# exit-code   1              
# env-file    ~/.opam/log/ssl-252336-8ef448.env
# output-file ~/.opam/log/ssl-252336-8ef448.out
### output ###
# compiling c program:
# [...]
#  | #endif
#  | 
# run: musl-gcc -O2 -fno-strict-aliasing -fwrapv -fPIC -Os -I /home/abcxyz/testthis/_opam/lib/ocaml -o /opam-tmp/buildc90f89.dune/ocaml-configurator0a154c/c-test-3/test
.o -c /opam-tmp/buildc90f89.dune/ocaml-configurator0a154c/c-test-3/test.c
# -> process exited with code 1
# -> stdout:
# -> stderr:
#  | /opam-tmp/buildc90f89.dune/ocaml-configurator0a154c/c-test-3/test.c:2:10: fatal error: openssl/ssl.h: No such file or directory
#  |     2 | #include <openssl/ssl.h>
#  |       |          ^~~~~~~~~~~~~~~
#  | compilation terminated.
# Error: failed to compile program



<><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
+- The following actions failed
| - build ssl 0.5.10
+- 

Fixing the SSL accept bug in a released version

The commit in 13f860b is necessary for Lwt_ssl.accept to work at all (otherwise it just throws an exception immediately). Would it be ok if I cherry pick this into an OPAM-only patch for now?

Unfortunately the master of this repository doesn't work for me currently due to missing symbols from the TLSv1.1/1.2 addition with this version in MacOS X.

$ openssl version
OpenSSL 0.9.8y 5 Feb 2013

So patching the accept bug would help unblock the Lwt_ssl support in Cohttp (see https://github.com/mirage/ocaml-conduit for the code, in lib/lwt_unix_net_ssl.ml)

Add a tag

You released 0.4.7 but without tagging it in this repo, making it impossible to download it from the "releases" pages. Please add a git tag.

Wrong clause number in LGPL special exception

The special exception part of the license file says:

By "a publicly distributed version of the Library", we mean either the unmodified Library, or a modified version of the Library that is distributed under the conditions defined in clause 3 of the GNU Library General Public License.

It should be "clause 2", not "clause 3".

This is the same typo made in OCaml's license: ocaml/ocaml@2d26308

Linking with Ssl causes segfault on multicore OCaml

I've been investigating why Dream segfaults when run on multicore (see aantron/dream#191).

I've managed to simplify the test-case to this (with ssl as its only dependency):

let foo = Ssl.file_descr_of_socket

let () =
  while true do
    Gc.full_major ()
  done

This segfaults immediately for me when run under ocaml-variants.4.12.0+domains.

I believe the cause is this bit of ssl.ml:

ocaml-ssl/src/ssl.ml

Lines 191 to 193 in b711cd4

external get_client_verify_callback_ptr : unit -> verify_callback = "ocaml_ssl_get_client_verify_callback_ptr"
let client_verify_callback = get_client_verify_callback_ptr ()

The C stub is

ocaml-ssl/src/ssl_stubs.c

Lines 562 to 565 in b711cd4

CAMLprim value ocaml_ssl_get_client_verify_callback_ptr(value unit)
{
return (value)client_verify_callback;
}

However, client_verify_callback is not an OCaml value, it's a C function. This causes the GC to crash when trying to mark it.

simplify/optimize c interface

  • a lot of functions that can not block should probably not release the runtime system (like embed_socket or get_file_descr)
  • a lot of functions could be tagged @@noalloc if raising the exception was done on OCaml side (like get_file_descr).

Do we want to provide the apriori fastest possible binding (as long as they remain safe and simple) ?

Do not force SSL_MODE_AUTO_RETRY

Currently all context have this flag, which is bad in non blocking context with eio or simple_httpd as the scheduler will loose opportunities to switch task.

opam install ssl (0.5.5) error

opam install ssl (0.5.5) returns an error on Darwin (macOS) that didn't happen with 0.5.4:

... CPPFLAGS=-I/usr/local/opt/openssl/include LDFLAGS=-L/usr/local/opt/openssl/lib
# configure: error: Cannot find libssl headers.

There is no “/usr/local/opt” in Darwin.

The same error occurs when I create “/usr/local/opt/openssl” and put symbolic links to existing openssl directories there.

Could it be that the “opam” file (new in 0.5.5) is faulty? The “opam” in the conf-openssl package looks different.

Bindings for more ERR_* functions

I suggest adding bindings for, at least, ERR_get_error, ERR_lib_error_string and ERR_reason_error_string (not necessarily as separate functions). ocaml-ssl currently binds ERR_error_string_n(ERR_get_error(), ...) as get_error_string and uses it for its registered exception printer. However, the default format has proven hard to read in Dream logs. We'd like to print these errors with a custom format.

These may need to be returned in a single call if using ERR_get_error, since it pops the error from the stack. (Is it documented that get_error_string and Printexc.to_string only work once as well? Maybe these functions should use ERR_peek_error instead.)

New release? (0.5.11)

Hi! A friend and I are writing a Gemini client and to implement TOFU we need the X509_digest function (#66) which is included in version 0.5.11.
Could you publish it? Thanks a lot in advance and have a nice day!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.