Hi,
i am just two days on Ocaml…
i want to query two different rest-services and match the results.
First one is done
The second one is missing something in the cert chain
openssl says
Verify return code: 21 (unable to verify the first certificate)
In java i can add the servers cert to a truststore, is something like that available Cohttp_lwt_unix?
It seems i can create a ssl_config with something like this…
open Tls.Config
let ssl_config = (Tls.Config.client…
but how to wire it up?
A bit of an example would be nice, since i am scratching my head over the docs for several hours
Btw. i can query with the curly package so a not so strict certification check would also do…
utop # match p with
|Ok cert -> Tls.Config.client ~certificates:(`Single cert)
| Error (`Msg msg) ->
failwith ("Failed to load certificate: " ^ msg);;
Error: This expression has type X509.Certificate.t
but an expression was expected of type
Tls.Config.certchain = X509.Certificate.t list * X509.Private_key.t
Since i have no private key for this…
Someone has a suggestion for a http client lib where this is possible?
A certificate is by definition public. Anyone can get, let’s say, the ocaml.org certificate. If you want to have an HTTPS server that authenticates itself, you MUST have the associated private key. This private key should be generated with your certificate by your CA (certificate authority). (You may have more complex protocol where you generate a private key with a certificate request, then the CA gives you the corresponding certificate… but you still have a private key)
The OCaml expression which gives you this key is typically:
I have an Apache server with certificates/keys provided by Letsencrypt. The /etc/letsencrypt/live/__my_host__/ contains fullchain.pem, the certificate, but also privkey.pem, the private key.
I note a certificate LIST is expected. I don’t now if a list with just your certificate would be enough. A certificate is already a chain of certification from a root certificate to the “subject” of the certificate. The fullchain.pem from Letsencrypt is such a certificate. But Letsencrypt also provides partial certificates like cert.pem which need to be completed by an intermediate certificate.
And if you generate a self-signed certificate by openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem, you have the key in a key.pem file.
Hi Frederic,
thanks for the explanation!
Maybe i confuse something or didn’t get the TLS to the full point…
I am on the client side…
In my understanding i should obtain the public part with openssl or from the browser and tell the client to trust this.
Let’s say the server i want to query is ocaml.org (with that improper cert)… i would never get the private key…
What i did in java btw. clojure downloaded the public cert and imported it into a keystore.
like
openssl s_client -connect server:443 2>&1 </dev/null | sed -ne '/BEGIN CERT/,/END CERT/p' | openssl x509 -outform der > server.der
keytool -import -noprompt -alias Server -keystore $KEYSTORE -storepass mypass -file server.der
Thank you very much for this example!
With some minor tweaks i got it running
These drove me crazy lwt authenticator
thought that it was a typo and should be let
So for other total newcomers to ocaml here is the updated code
Adding this to dune file…
(preprocess
(pps lwt_ppx))
this works
open Lwt
let main host port =
let%lwt authenticator = X509_lwt.authenticator (`Ca_file "/dir/test.pem") in
let%lwt (ic, oc) = Tls_lwt.connect authenticator (host, port) in
let req = String.concat "\r\n" [
"GET / HTTP/1.1" ; "Host: " ^ host ; "Connection: close" ; "" ; ""
] in
Lwt_io.(write oc req >>= fun () -> read ic >>= print)
let () =
let host = "www.myserver.com" in
let port = 443 in
Lwt_main.run (main host port)
Additionally i had to dig up the root cert and put to the downloaded one to get a full chain…
let httpcall2 =
let%lwt authenticator = X509_lwt.authenticator (`Ca_file "/.../test.pem") in
let reply, body = response_accumulator () in
let%lwt _ = Http_lwt_client.request ~authenticator:authenticator ~meth:`GET "https://myserver" reply () in
Lwt.return (reply,body)
Got only DNS timeouts with this lib yesterday while the Tls_lwt.connect still worked, today it magically works…
We know that we currently have an outcome that may be more about happy-eyeballs. If you could do an issue on this so we can reproduce and try to find a solution .
Yes, it depends on the DNS resolver used, its cache, and of course the speed between you and the resolver. “A better connection” may indeed solve the problem . That’s why we want to have some concrete cases, because we suspect our implementation has a bug.
FWIW http-lwt-client (or really the underlying happy-eyeballs implementation) does not work well with the DNS resolver on my home router. The router listens on tcp port 53 but does not respond. This is an annoying failure mode that could be handled more nicely. I will open an issue on that.