• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

esl / MongooseIM / 16499779126

24 Jul 2025 02:03PM UTC coverage: 85.593% (-0.02%) from 85.614%
16499779126

Pull #4549

github

jacekwegr
Add TODO comments
Pull Request #4549: Support Erlang 28

50 of 68 new or added lines in 5 files covered. (73.53%)

289 existing lines in 7 files now uncovered.

28945 of 33817 relevant lines covered (85.59%)

51736.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.29
/src/cert_utils.erl
1
%%%=============================================================================
2
%%% @copyright (C) 1999-2018, Erlang Solutions Ltd
3
%%% @author Denys Gonchar <denys.gonchar@erlang-solutions.com>
4
%%% @doc a dedicated module to provide SSL certificate parsing functionality.
5
%%% @end
6
%%%=============================================================================
7
-module(cert_utils).
8
-copyright("2018, Erlang Solutions Ltd.").
9
-author('denys.gonchar@erlang-solutions.com').
10

11
-include("mongoose_logger.hrl").
12

13
-export([get_cert_domains/1,
14
         get_common_name/1,
15
         get_xmpp_addresses/1
16
]).
17

18
-include_lib("public_key/include/public_key.hrl").
19
-include("XmppAddr.hrl").
20
-include("jlib.hrl").
21

22
-type certificate() :: binary() | #'Certificate'{} | #'OTPCertificate'{}.
23
-type general_name() :: term().
24

25
-spec get_common_name(certificate()) -> bitstring() | error.
26
get_common_name(Cert) ->
27
    try
535✔
28
        Cert1 = ensure_cert(Cert),
535✔
29
        #'OTPCertificate'{tbsCertificate = TBSCert} = Cert1,
535✔
30
        #'OTPTBSCertificate'{subject = {rdnSequence, RDNs}} = TBSCert,
535✔
31
        CNs = [V || RDN <- RDNs,
535✔
32
                     #'AttributeTypeAndValue'{type = ?'id-at-commonName', value = V} <- RDN],
697✔
33
        case CNs of
535✔
34
            [CN0 | _] ->
35
                normalize_dirstring(CN0);
535✔
36
            [] ->
NEW
37
                error
×
38
         end
39
    catch
40
        Class:Exception:StackTrace ->
41
            log_exception(Cert, Class, Exception, StackTrace),
×
42
            error
×
43
    end.
44

45

46
-spec get_xmpp_addresses(certificate()) -> [bitstring()].
47
get_xmpp_addresses(Cert) ->
48
    try
535✔
49
        Cert1 = ensure_cert(Cert),
535✔
50
        SANs = subject_alt_names(Cert1),
535✔
51
        XmppAddrs =
535✔
52
            [maybe_decode_xmpp(unwrap_asn1(Val))
393✔
53
             || {otherName, ON} <- SANs,
535✔
54
                {Oid, Val} <- [unwrap_othername(ON)],
393✔
55
                Oid =:= ?'id-on-xmppAddr'],
393✔
56
        [Addr || Addr <- XmppAddrs, is_binary(Addr)]
535✔
57
    catch
58
        Class:Exception:StackTrace ->
59
            log_exception(Cert, Class, Exception,StackTrace),
×
60
            []
×
61
    end.
62

63

64
-spec get_dns_addresses(certificate()) -> [string()].
65
get_dns_addresses(Cert) ->
66
    try
54✔
67
        Cert1 = ensure_cert(Cert),
54✔
68
        SANs = subject_alt_names(Cert1),
54✔
69
        [DNS || {dNSName, DNS} <- SANs]
54✔
70
    catch
71
        Class:Exception:StackTrace ->
72
            log_exception(Cert, Class, Exception, StackTrace),
×
73
            []
×
74
    end.
75

76

77
-spec get_cert_domains(certificate()) -> [bitstring()].
78
get_cert_domains(Cert) ->
79
    Cert1 = ensure_cert(Cert),
54✔
80
    CN = get_common_name(Cert1),
54✔
81
    Addresses = get_xmpp_addresses(Cert1),
54✔
82
    Domains = get_dns_addresses(Cert1),
54✔
83
    lists:append([get_lserver_from_addr(CN, false) |
54✔
84
                  [get_lserver_from_addr(Addr, true) || Addr <- Addresses, is_binary(Addr)] ++
×
85
                  [get_lserver_from_addr(DNS, false) || DNS <- Domains, is_list(DNS)]]).
324✔
86

87

88
convert_to_bin(Val) when is_list(Val) ->
89
    list_to_binary(Val);
324✔
90
convert_to_bin(Val) ->
91
    Val.
54✔
92

93
-spec get_lserver_from_addr(bitstring() | string(), boolean()) -> [binary()].
94
get_lserver_from_addr(V, UTF8) when is_binary(V); is_list(V) ->
95
    Val = convert_to_bin(V),
378✔
96
    case {jid:from_binary(Val), UTF8} of
378✔
97
        {#jid{luser = <<"">>, lserver = LD, lresource = <<"">>}, true} ->
98
            case mongoose_s2s_lib:domain_utf8_to_ascii(LD, binary) of
×
99
                false -> [];
×
100
                PCLD -> [PCLD]
×
101
            end;
102
        {#jid{luser = <<"">>, lserver = LD, lresource = <<"">>}, _} -> [LD];
108✔
103
        _ -> []
270✔
104
    end;
105
get_lserver_from_addr(_, _) -> [].
×
106

107

108
log_exception(_Cert, Class, Exception, StackTrace) ->
109
    ?LOG_ERROR(#{what => <<"cert_parsing_failed">>,
×
110
                 text => <<"failed to parse certificate">>,
111
                 class => Class, reason => Exception, stacktrace => StackTrace}).
×
112

113
-spec ensure_cert(certificate()) -> #'OTPCertificate'{}.
114
ensure_cert(#'OTPCertificate'{} = Cert) ->
115
    Cert;
162✔
116
ensure_cert(#'Certificate'{} = PlainCert) ->
117
    Der = public_key:pkix_encode('Certificate', PlainCert, plain),
1,016✔
118
    public_key:pkix_decode_cert(Der, otp);
1,016✔
119
ensure_cert(Bin) when is_binary(Bin) ->
NEW
120
    public_key:pkix_decode_cert(Bin, otp).
×
121

122
-spec subject_alt_names(#'OTPCertificate'{}) -> [general_name()].
123
subject_alt_names(#'OTPCertificate'{tbsCertificate = TBSCert}) ->
124
    #'OTPTBSCertificate'{extensions = Exts} = TBSCert,
589✔
125
    case lists:keyfind(?'id-ce-subjectAltName', #'Extension'.extnID, Exts) of
589✔
126
        #'Extension'{extnValue = SANs} -> SANs;
589✔
NEW
127
        false -> []
×
128
    end.
129

130
maybe_decode_xmpp(Bin) when is_binary(Bin) ->
131
    case 'XmppAddr':decode('XmppAddr', Bin) of
393✔
132
        {ok, XmppAddr} -> XmppAddr;
393✔
133
        Error ->
NEW
134
            ?LOG_INFO(#{what => get_xmpp_addresses_failed, reason => Error}),
×
NEW
135
            ok
×
136
    end;
137
maybe_decode_xmpp(_) ->
NEW
138
    ok.
×
139

140
normalize_dirstring({utf8String, Bin}) when is_binary(Bin) -> Bin;
535✔
NEW
141
normalize_dirstring({printableString, Str}) when is_list(Str) -> list_to_binary(Str);
×
NEW
142
normalize_dirstring({ia5String, Str}) when is_list(Str) -> list_to_binary(Str);
×
NEW
143
normalize_dirstring(Bin) when is_binary(Bin) -> Bin;
×
NEW
144
normalize_dirstring(Str) when is_list(Str) -> list_to_binary(Str).
×
145

NEW
146
unwrap_asn1({'INSTANCE OF', _Oid, Bin}) when is_binary(Bin) -> Bin;
×
NEW
147
unwrap_asn1({asn1_OPENTYPE, Bin}) -> Bin;
×
148
unwrap_asn1(Bin) when is_binary(Bin) -> Bin.
393✔
149

150
unwrap_othername({'INSTANCE OF', Oid, Val}) -> {Oid, Val};
284✔
151
%% TODO: Remove this clause once we drop support for OTP 27,
152
%% which uses a 3-tuple {AnotherName, Oid, Val} format for OtherName.
153
unwrap_othername(Another)
154
    when is_tuple(Another),
155
         tuple_size(Another) =:= 3,
156
         element(1, Another) =:= 'AnotherName' ->
157
    {element(2, Another), element(3, Another)}.
109✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc