[erlang-questions] ssl certificate verification in httpc

Camille Troillard lists@REDACTED
Thu Jul 17 13:20:02 CEST 2014

Hello Ivan,

I have the same issue, here is what I came up to. This may not be correct and I would be very happy to discuss the issues anyone may find.  My goal is to check the server certificate is valid using verify_peer, and also implement a check on the server hostname I connect to.

Here are the SSL options I use:

% I know the certificate used by the server requires a depth of 2, you may not need this option in your code.

        {ssl, [
            {cacertfile, cacert_path()},
            {depth, 2},
            {verify_fun, ssl_verify_fun(?SERVER_HOSTNAME)},
            {verify, verify_peer}

And the verify fun:

ssl_verify_fun(Hostname) ->
        fun (_, {bad_cert, _} = Reason, _) ->
                {fail, Reason};
            (_, {extension, _}, UserState) ->
                {unknown, UserState};
            (_, valid, UserState) ->
                {valid, UserState};
            (Cert, valid_peer, UserState) ->
                TBSCert = Cert#'OTPCertificate'.tbsCertificate,
                Extensions = TBSCert#'OTPTBSCertificate'.extensions,
                case lists:keysearch(?'id-ce-subjectAltName', #'Extension'.extnID, Extensions) of
                    {value, #'Extension'{extnValue = [{dNSName, Hostname}]}} ->
                        {valid, UserState};
                    false ->
                        {fail, invalid_certificate_hostname}

As you can see, I verify the host name matches the one I am connecting to.


On 17 Jul 2014, at 11:30, Ivan Uemlianin <ivan@REDACTED> wrote:

> Dear Roger
> Thank you for your comments.
> Your comments take us back to my initial question:
> > In short, what am I missing to be able to verify this certificate?
> Just providing the CA certificate doesn't seem to be enough:
> > ...
>>    SSLOpts = [{verify, verify_peer},
>>               {cacertfile,"certificates.crt"}],
>>    httpc:request(get, {Url, []}, [{ssl,SSLOpts}], []).
>> But this returns an unknown ca error:
>>    {error,{failed_connect,[{to_address,{"bla.org", 443}},
>>                            {inet,[inet],{tls_alert,"unknown ca"}}]}}
>>    11:06:04.942 [error] SSL: certify: ssl_handshake.erl:1344:
> >     Fatal error: unknown ca
> None of the other ssl options in the erlang ssl documentation look likely, and I have found no examples of verifying an ssl certification from erlang on the web.
> - are any of the other ssl options relevant here?  Are there other undocumented ssl options?
> - failing that, it looks like I need to write a verify_fun and access parts of the OTPCertificate and Extension records.  Is that correct, or is more required?
> - I have scoured the usual sources on the web but found nothing.  If anyone knows of relevant work in this area please let me know.
> Thanks
> Ivan
> On 17/07/2014 08:08, Roger Lipscombe wrote:
>> SSL encryption is done by the client creating a session key, and using
>> the server's public key (from the server's certificate) to securely
>> send it to the server. If you don't verify the server certificate, you
>> have no way of knowing whether you're subject to a man-in-the-middle
>> attack, where the attacker can give you a fake certificate, extract
>> the session key, read/manipulate all your traffic, and then
>> (optionally) send it to the real server.
>> Encryption is only half of the story. SSL also aims to guarantee safe
>> key exchange, but to do that, you need to verify the server
>> certificate. This means verifying that the names match, that it's
>> trusted (or issued by a trusted CA), and that it hasn't expired, been
>> revoked, etc.
>> And there's more than one way (also including DNS spoofing) to
>> intercept the traffic: transparent proxies, pwned WiFi router, etc..
>> On 15 July 2014 15:41, Camille Troillard <lists@REDACTED> wrote:
>>> Hi Robert,
>>>> SSL essentially does two things at once: encrypts the data and checks if client and/or server are who they say they are. The latter is where certificate verification comes into play, the encryption part is always done and usually automatically negotiated between client and server.
>>>> So, if all you are aiming for is encrypting the data travelling between client and server, then you don't need the ssl option. Just point your httpc:request at an "https://..." URL and the encryption is handled for you without you having to do anything more.
>>> I think this works only if you trust your DNS, otherwise you have to check that the certificate matches the host.
>>> Please correct me if I’m wrong.
>>> Cam
>>> _______________________________________________
>>> erlang-questions mailing list
>>> erlang-questions@REDACTED
>>> http://erlang.org/mailman/listinfo/erlang-questions
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED
>> http://erlang.org/mailman/listinfo/erlang-questions
> -- 
> ============================================================
> Ivan A. Uemlianin PhD
> Llaisdy
> Speech Technology Research and Development
>                    ivan@REDACTED
>                     www.llaisdy.com
>                         llaisdy.wordpress.com
>              github.com/llaisdy
>                     www.linkedin.com/in/ivanuemlianin
>                        festina lente
> ============================================================
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions

More information about the erlang-questions mailing list