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