1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2015-2017. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19 20%---------------------------------------------------------------------- 21%% Purpose: CRL handling 22%%---------------------------------------------------------------------- 23 24-module(ssl_crl). 25 26-include("ssl_alert.hrl"). 27-include("ssl_internal.hrl"). 28-include_lib("public_key/include/public_key.hrl"). 29 30-export([trusted_cert_and_path/4]). 31 32trusted_cert_and_path(CRL, {SerialNumber, Issuer}, CertPath, {Db, DbRef}) -> 33 %% CRL issuer cert ID is known 34 case ssl_pkix_db:lookup_trusted_cert(Db, DbRef, SerialNumber, Issuer) of 35 undefined -> 36 %% But not found in our database 37 search_certpath(CRL, CertPath, Db, DbRef); 38 {ok, #cert{otp=OtpCert}} -> 39 {ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef), 40 {ok, Root, lists:reverse(Chain)} 41 end; 42trusted_cert_and_path(CRL, issuer_not_found, CertPath, {Db, DbRef}) -> 43 case search_certpath(CRL, CertPath, Db, DbRef) of 44 {error, unknown_ca} -> 45 Issuer = public_key:pkix_normalize_name(public_key:pkix_crl_issuer(CRL)), 46 IsIssuerFun = 47 fun({_Key, CertCandidate}, Acc) -> 48 verify_crl_issuer(CRL, CertCandidate, Issuer, Acc); 49 (_, Acc) -> 50 Acc 51 end, 52 case search_db(IsIssuerFun, Db, DbRef) of 53 {ok, OtpCert} -> 54 {ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef), 55 {ok, Root, lists:reverse(Chain)}; 56 {error, issuer_not_found} -> 57 {error, unknown_ca} 58 end; 59 Result -> 60 Result 61 end. 62 63search_certpath(CRL, CertPath, Db, DbRef) -> 64 Issuer = public_key:pkix_normalize_name(public_key:pkix_crl_issuer(CRL)), 65 IsIssuerFun = 66 fun(CertCandidate, Acc) -> 67 verify_crl_issuer(CRL, CertCandidate, Issuer, Acc) 68 end, 69 case find_issuer(IsIssuerFun, certpath, CertPath) of 70 {ok, OtpCert} -> 71 {ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef), 72 {ok, Root, lists:reverse(Chain)}; 73 {error, issuer_not_found} -> 74 {error, unknown_ca} 75 end. 76 77search_db(IsIssuerFun, _, {extracted, ExtractedCerts})-> 78 find_issuer(IsIssuerFun, extracted, ExtractedCerts); 79search_db(IsIssuerFun, Db, DbRef) -> 80 find_issuer(IsIssuerFun, Db, DbRef). 81 82find_issuer(IsIssuerFun, certpath, Certs) -> 83 try lists:foldl(IsIssuerFun, issuer_not_found, Certs) of 84 issuer_not_found -> 85 {error, issuer_not_found} 86 catch 87 {ok, _} = Result -> 88 Result 89 end; 90find_issuer(IsIssuerFun, extracted, CertsData) -> 91 Certs = [Entry || {decoded, Entry} <- CertsData], 92 try lists:foldl(IsIssuerFun, issuer_not_found, Certs) of 93 issuer_not_found -> 94 {error, issuer_not_found} 95 catch 96 {ok, _} = Result -> 97 Result 98 end; 99find_issuer(IsIssuerFun, Db, _) -> 100 try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, Db) of 101 issuer_not_found -> 102 {error, issuer_not_found} 103 catch 104 {ok, _} = Result -> 105 Result 106 end. 107 108verify_crl_issuer(CRL, #cert{otp = OTPCertCandidate}, Issuer, NotIssuer) -> 109 TBSCert = OTPCertCandidate#'OTPCertificate'.tbsCertificate, 110 case public_key:pkix_normalize_name(TBSCert#'OTPTBSCertificate'.subject) of 111 Issuer -> 112 case public_key:pkix_crl_verify(CRL, OTPCertCandidate) of 113 true -> 114 throw({ok, OTPCertCandidate}); 115 false -> 116 NotIssuer 117 end; 118 _ -> 119 NotIssuer 120 end. 121