diff options
Diffstat (limited to 'lib/ssl/src/ssl_crl_hash_dir.erl')
-rw-r--r-- | lib/ssl/src/ssl_crl_hash_dir.erl | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/lib/ssl/src/ssl_crl_hash_dir.erl b/lib/ssl/src/ssl_crl_hash_dir.erl new file mode 100644 index 0000000000..bb62737232 --- /dev/null +++ b/lib/ssl/src/ssl_crl_hash_dir.erl @@ -0,0 +1,106 @@ +%% +%% %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"). + +-behaviour(ssl_crl_cache_api). + +-export([lookup/3, select/2, fresh_crl/2]). + +lookup(#'DistributionPoint'{cRLIssuer = CRLIssuer} = DP, CertIssuer, CRLDbInfo) -> + Issuer = + case CRLIssuer of + asn1_NOVALUE -> + %% If the distribution point extension doesn't + %% indicate a CRL issuer, use the certificate issuer. + CertIssuer; + _ -> + CRLIssuer + end, + %% Find all CRLs for this issuer, and return those that match the + %% given distribution point. + AllCRLs = select(Issuer, CRLDbInfo), + lists:filter(fun(DER) -> + public_key:pkix_match_dist_point(DER, DP) + end, AllCRLs). + +fresh_crl(#'DistributionPoint'{}, CurrentCRL) -> + CurrentCRL. + +select(Issuer, {_DbHandle, [{dir, Dir}]}) -> + case find_crls(Issuer, Dir) of + [_|_] = DERs -> + DERs; + [] -> + %% That's okay, just report that we didn't find any CRL. + %% If the crl_check setting is best_effort, ssl_handshake + %% is happy with that, but if it's true, this is an error. + []; + {error, Error} -> + error_logger:error_report( + [{cannot_find_crl, Error}, + {dir, Dir}, + {module, ?MODULE}, + {line, ?LINE}]), + [] + end. + +find_crls(Issuer, Dir) -> + case filelib:is_dir(Dir) of + true -> + Hash = public_key:short_name_hash(Issuer), + find_crls(Issuer, Hash, Dir, 0, []); + false -> + {error, not_a_directory} + end. + +find_crls(Issuer, Hash, Dir, N, Acc) -> + Filename = filename:join(Dir, Hash ++ ".r" ++ integer_to_list(N)), + case file:read_file(Filename) of + {error, enoent} -> + 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) + catch + error:Error -> + %% Something is wrong with the file. Report + %% it, and try the next one. + error_logger:error_report( + [{crl_parse_error, Error}, + {filename, Filename}, + {module, ?MODULE}, + {line, ?LINE}]), + find_crls(Issuer, Hash, Dir, N + 1, Acc) + 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. + |