extracting subjectAltName

Fredrik Thulin ft@REDACTED
Wed Sep 28 13:11:18 CEST 2005


On Monday 26 September 2005 16.35, Fredrik Thulin wrote:
> If I have a certificate structure returned by ssl:peercert/2, how do
> I extract the subjectAltName(s)?
...

Since there were no answers to my post, I figured there were no easy 
way. This is a post for the archives, in case anyone else wants to do 
this in the future.

First, I realized that ssl:peercert/2's option 'ssl' is useless on the 
bewildered Internet, as it crashes with a function_clause as soon as 
you try to use it on a certificate that contains any extensions that 
Erlang SSL is not aware of. This has been reported several times (by 
myself and others) on the mailing list, but nobody seems intersted in 
fixing it (yes, in my opinion it is something that should be fixed).

Use option 'pkix' instead, and then use the exported but not documented 
functions from the ssl application to make use of the results.

The following is from my file yxa/src/transportlayer/tcp_connection.erl, 
mildly modified to e-mail format. I use Erlang/OTP R10B-6 since Erlang 
SSL distibution is broken in R10B-7 (although I haven't received any 
responses from the OTP team when reporting this - nudge nudge).

-include_lib("ssl/include/SSL-PKIX.hrl").
...
    {ok, Cert} = ssl:peercert(Socket, [pkix]),
...
%%--------------------------------------------------------------------
%% Function: get_ssl_peer_info_host_altnames(Cert)
%%           Cert = 'Certificate' record, SSL PKIX parsed
%% Descrip.: Extracts subjectAltName's of type dNSName or iPAddress
%%           from an SSL PKIX certificate.
%% Returns : {ok, AltNames}
%%           AltNames = list() of string()
%%--------------------------------------------------------------------
get_ssl_peer_info_host_altnames(Cert) when is_record(Cert, 
						'Certificate') ->
    Extensions =
        (Cert#'Certificate'.tbsCertificate)#'TBSCertificate'.extensions,
    AltNameExtensions = get_tbs_extensions(
                          ssl_pkix_oid:atom2id(subjectAltName),
                          Extensions),
    {ok, DNS_altNames} = get_host_altnames('SubjectAltName',
                                           AltNameExtensions),
    {ok, DNS_altNames}.

%% get_tbs_extensions/2 - part of get_ssl_peer_info_host_altnames/1
%% Returns : list() of 'Extension' record
get_tbs_extensions(Key, Extensions) ->
    get_tbs_extensions(Key, Extensions, []).

get_tbs_extensions(Key, [#'Extension'{extnID = Key} = H | T], Res) ->
    get_tbs_extensions(Key, T, [H | Res]);
get_tbs_extensions(Key, [H | T], Res) when is_record(H, 'Extension') ->
    get_tbs_extensions(Key, T, Res);
get_tbs_extensions(_Key, [], Res) ->
    lists:reverse(Res).

%% get_dns_altnames(Type, Extensions) -
%% part of get_ssl_peer_info_host_altnames/1
%% Returns : {ok, Strings}
get_host_altnames(Type, Extensions) ->
    get_host_altnames(Type, Extensions, []).

get_host_altnames(Type, [#'Extension'{extnValue = Value} | T], Res) ->
    {ok, Decoded} = 'PKIX1Implicit88':decode(Type,
                                             list_to_binary(Value)),
    %% Decoded is a list of tuples, for example :
    %%   [{rfc822Name, "ft@REDACTED"},
    %%    {dNSName,    "sip.example.org"}]
    This = lists:foldl(fun({dNSName, Name}, Acc) when is_list(Name) ->
                               [http_util:to_lower(Name) | Acc];
                          ({iPAddress, IP}, Acc) when is_list(IP) ->
                               IPtuple = siphost:makeip(
						list_to_tuple(IP)),
                               [IPstr | Acc];
                          (_NonDNSname, Acc) ->
                               Acc
                       end, [], Decoded),
    case This of
        [] ->
            %% we found no dNSName or iPAddress tuples in Decoded
            get_host_altnames(Type, T, Res);
        _ ->
            get_host_altnames(Type, T, Res ++ This)
    end;
get_host_altnames(_Type, [], Res) ->
    {ok, Res}.

/Fredrik



More information about the erlang-questions mailing list