[erlang-questions] bad certificate if trying to verify StartSsl certificate

Ben Murphy <>
Sun Sep 13 23:22:25 CEST 2015


Just a note that this verify function is broken and accepts all self
signed certificates. :(

On Thu, Sep 10, 2015 at 11:44 AM, Ben Murphy <> wrote:
> I have a verify function that hacks around this problem. It adds the
> certs to a list during the 'verification' then it resorts and passes
> it off to the path validation. However, this function only supports
> validation from a single root cert because we are using it in
> production to connect to a server that has a chain signed by a
> non-public CA. You use it like: {verify_fun,
> fixed_root_lenient_verifier:create_verify_function(DerCaCert, 10)}
>
> Use this module at your own risk it may effectively disable your SSL
> security. I really think this resorting should be done in OTP or OTP
> should supply a cleaner hook for resorting. A hook that gives you the
> chain and the cacerts and lets you send back a new chain would be
> perfect :)
>
> -module(fixed_root_lenient_verifier).
>
> -record(state, {certs = [], root_cert, max_path_length}).
>
> -export([verify/3]).
> -export([create_verify_function/2]).
>
> create_verify_function(DerCertificate, MaxPathLength) ->
>   DecodedCert = public_key:pkix_decode_cert(DerCertificate, otp),
>   {fun fixed_root_lenient_verifier:verify/3, #state{root_cert =
> DecodedCert, max_path_length = MaxPathLength}}.
>
> append_cert(State, Cert) ->
>   State#state{certs = [Cert | State#state.certs]}.
>
> default_verify(_Cert, Event, State) ->
>   case Event of
>     {bad_cert, Reason} ->  {fail, Reason};
>     {extension, _} -> {unknown, State};
>     valid -> {valid, State};
>     valid_peer -> {valid, State}
>   end.
>
>
> verify(Cert, Event, State) ->
>   case Event of
>     {bad_cert, _Reason} ->
>       {valid, append_cert(State, Cert)};
>     {extension, _} -> {unknown, State};
>     valid -> {valid, append_cert(State, Cert)};
>     valid_peer ->
>       case final_verification(State#state.certs, Cert,
> State#state.max_path_length, State#state.root_cert) of
>         {ok, _} -> {valid, State};
>         {error, Reason} -> {fail, Reason}
>       end
>   end.
>
> final_verification(Certs, PeerCert, MaxPathLength, RootCertificate) ->
>   Chain = fix_path(PeerCert, Certs),
>   public_key:pkix_path_validation(RootCertificate, Chain,
> [{max_path_length, MaxPathLength}, {verify_fun, {fun default_verify/3,
> none}}]).
>
>
> fix_path(Peer, RestOfChain) ->
>   make_chain(Peer, RestOfChain, []).
>
> make_chain(OtpCert, CertChain, ResultChain) ->
>   case public_key:pkix_is_self_signed(OtpCert) of
>     true ->
>       [OtpCert | ResultChain ];
>     false ->
>         case find_issuer(OtpCert, CertChain) of
>           {ok, NewCert, NewCertChain} ->
>             % we remove the cert that was found from the chain
>             % to prevent infinite loops where a chain becomes
>             % a loop
>             make_chain(NewCert, NewCertChain, [OtpCert | ResultChain]);
>           {error, issuer_not_found} ->
>             % assume it is the 'trusted' certificate
>             [OtpCert | ResultChain]
>         end
>   end.
>
> find_issuer(OtpCert, CertChain) ->
>   {Not, Maybe} = lists:splitwith(fun(Candidate) ->
>     not public_key:pkix_is_issuer(OtpCert, Candidate)
>   end, CertChain),
>
>   case Maybe of
>     [Issuer | Rest] ->
>       {ok, Issuer, Not ++ Rest};
>     [] ->
>       {error, issuer_not_found}
>   end.
>
> On Thu, Sep 10, 2015 at 10:02 AM, Benoit Chesneau <> wrote:
>> I
>> On Tue, Aug 11, 2015 at 9:54 AM Ingela Andin <> wrote:
>>>
>>> Hi!
>>>
>>> 2015-07-16 11:16 GMT+02:00 Alex Hudich <>:
>>>>
>>>> Hi!
>>>>
>>>>
>>>>
>>>> wget http://curl.haxx.se/ca/cacert.pem
>>>>
>>>> and then
>>>>
>>>> ssl:connect( "www.nicemine.ru", 443,
>>>> [{verify,verify_peer},{server_name_indication,"www.nicemine.ru"},{depth,2},{cacertfile,"cacert.pem"}]
>>>> ).
>>>>
>>>> gives me {error,{tls_alert,"bad certificate"}}
>>>>
>>>>
>>>>
>>>
>>> This site is not sending a correct certificate chain,  I get all the
>>> certificates that shall be in the chain but scrambled around and not in the
>>> correct order, this is breaking the
>>> SSL/TLS-protocol. OpenSSL will also get the error above when trying to
>>> verify that chain, but later versions of OpenSSL and also other
>>> implementations obviously tries to work around this by attempting to sort
>>> them and run the validation again.
>>>
>>> You could do that too using the verify_fun if you really want to. We would
>>> rather not make that a default feature as breaking security protocols is
>>> usually a bad idea that could lead to vulnerabilities.
>>>
>>>
>>> Regards Ingela Erlang/OTP Team - Ericsson AB
>>>
>>
>>
>> I have the same issue on another host: rest-api.pay.nl:
>>
>> 15> ssl:connect( "rest-api.pay.nl", 443,
>> [{verify,verify_peer},{server_name_indication,"rest-api.pay.nl"},{depth,2},{cacertfile,
>> "priv/ca-bundle.crt"}] ).
>>
>> =ERROR REPORT==== 10-Sep-2015::11:01:31 ===
>> SSL: certify: ssl_handshake.erl:1476:Fatal error: bad certificate
>> {error,{tls_alert,"bad certificate"}}
>>
>>
>> the chain looks correct for me and curl handle it without issue. What do you
>> mean by sorting certificates ? Any example?
>>
>> - benoit
>>
>>
>>
>>>
>>>
>>>>
>>>> Why? Site can be opened ok in the browser.
>>>>
>>>> Erlang/OTP 17 [erts-6.3]
>>>>
>>>>
>>>> _______________________________________________
>>>> erlang-questions mailing list
>>>> 
>>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>
>>> _______________________________________________
>>> erlang-questions mailing list
>>> 
>>> http://erlang.org/mailman/listinfo/erlang-questions
>>
>>
>> _______________________________________________
>> erlang-questions mailing list
>> 
>> http://erlang.org/mailman/listinfo/erlang-questions
>>


More information about the erlang-questions mailing list