1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2016-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
-module(ssl_crl_hash_dir).
-include_lib("public_key/include/public_key.hrl").
-include_lib("kernel/include/logger.hrl").
-behaviour(ssl_crl_cache_api).
-export([lookup/3, select/2, fresh_crl/2]).
lookup(#'DistributionPoint'{cRLIssuer = CRLIssuer} = DP, CertIssuer, CRLDbInfo) ->
case CRLIssuer of
asn1_NOVALUE ->
%% If the distribution point extension doesn't
%% indicate a CRL issuer, use the certificate issuer.
select(CertIssuer, CRLDbInfo);
_ ->
CRLs = select(CRLIssuer, CRLDbInfo),
lists:filter(fun(DER) ->
public_key:pkix_match_dist_point(DER, DP)
end, CRLs)
end.
fresh_crl(#'DistributionPoint'{}, CurrentCRL) ->
CurrentCRL.
select({rdnSequence, _} = Issuer, DbHandle) ->
select([{directoryName, Issuer}], DbHandle);
select([], _) ->
[];
select([{directoryName, Issuer} | _], {_DbHandle, [{dir, Dir}]}) ->
case find_crls(public_key:pkix_normalize_name(Issuer), Dir) of
{#{reason := []}, DERs} ->
DERs;
{#{reason := [_|_]} = Report, DERs} ->
{logger, {notice, Report, ?LOCATION}, DERs};
{error, Error} ->
{logger, {error, #{description => "CRL retrival",
reason => [{cannot_find_crl, Error},
{dir, Dir}]}, ?LOCATION}, []}
end;
select([_ | Rest], CRLDbInfo) ->
select(Rest, CRLDbInfo).
find_crls(Issuer, Dir) ->
case filelib:is_dir(Dir) of
true ->
Hash = public_key:short_name_hash(Issuer),
find_crls(Issuer, Hash, Dir, 0, [], #{description => "CRL file traversal",
reason => []});
false ->
{error, not_a_directory}
end.
find_crls(Issuer, Hash, Dir, N, Acc, #{reason := Reason} = Report) ->
Filename = filename:join(Dir, Hash ++ ".r" ++ integer_to_list(N)),
case file:read_file(Filename) of
{error, enoent} ->
{Report, Acc};
{ok, Bin} ->
try maybe_parse_pem(Bin) of
DER when is_binary(DER) ->
%% Found one file. Let's see if there are more.
find_crls(Issuer, Hash, Dir, N + 1, [DER] ++ Acc, Report)
catch
error:Error ->
%% Something is wrong with the file. Report
%% it, and try the next one.
find_crls(Issuer, Hash, Dir, N + 1, Acc, Report#{reason => [{{crl_parse_error, Error},
{filename, Filename}} | Reason]})
end
end.
maybe_parse_pem(<<"-----BEGIN", _/binary>> = PEM) ->
%% It's a PEM encoded file. Need to extract the DER
%% encoded data.
[{'CertificateList', DER, not_encrypted}] = public_key:pem_decode(PEM),
DER;
maybe_parse_pem(DER) when is_binary(DER) ->
%% Let's assume it's DER-encoded.
DER.
|