From 036a9c4edd013b8a97e5075e3da10b68698d2916 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 11 Mar 2013 09:53:44 +0100 Subject: ssl: Rename ssl_certificate_db to ssl_pkix_db for clarity Conflicts: lib/ssl/src/ssl.app.src lib/ssl/src/ssl_manager.erl --- lib/ssl/src/Makefile | 2 +- lib/ssl/src/ssl.app.src | 2 +- lib/ssl/src/ssl_certificate.erl | 2 +- lib/ssl/src/ssl_certificate_db.erl | 253 ------------------------------------- lib/ssl/src/ssl_connection.erl | 4 +- lib/ssl/src/ssl_handshake.erl | 2 +- lib/ssl/src/ssl_manager.erl | 31 ++--- lib/ssl/src/ssl_pkix_db.erl | 253 +++++++++++++++++++++++++++++++++++++ 8 files changed, 275 insertions(+), 274 deletions(-) delete mode 100644 lib/ssl/src/ssl_certificate_db.erl create mode 100644 lib/ssl/src/ssl_pkix_db.erl (limited to 'lib/ssl') diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index 3b8145089e..53edeaf767 100644 --- a/lib/ssl/src/Makefile +++ b/lib/ssl/src/Makefile @@ -48,7 +48,7 @@ MODULES= \ ssl_sup \ inet_tls_dist \ ssl_certificate\ - ssl_certificate_db\ + ssl_pkix_db\ ssl_cipher \ ssl_srp_primes \ ssl_connection \ diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src index 5c34de905e..06bf01e7e0 100644 --- a/lib/ssl/src/ssl.app.src +++ b/lib/ssl/src/ssl.app.src @@ -21,7 +21,7 @@ ssl_connection, ssl_cipher, ssl_srp_primes, - ssl_certificate_db, + ssl_pkix_db, ssl_certificate, ssl_alert ]}, diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 9e1c3a09bf..b186a1015a 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -240,7 +240,7 @@ find_issuer(OtpCert, CertDbHandle) -> Acc end, - try ssl_certificate_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of + try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of issuer_not_found -> {error, issuer_not_found} catch diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl deleted file mode 100644 index cdff73336e..0000000000 --- a/lib/ssl/src/ssl_certificate_db.erl +++ /dev/null @@ -1,253 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2013. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%%---------------------------------------------------------------------- -%% Purpose: Storage for trusted certificates -%%---------------------------------------------------------------------- - --module(ssl_certificate_db). - --include("ssl_internal.hrl"). --include_lib("public_key/include/public_key.hrl"). --include_lib("kernel/include/file.hrl"). - --export([create/0, remove/1, add_trusted_certs/3, - remove_trusted_certs/2, insert/3, remove/2, clear/1, db_size/1, - ref_count/3, lookup_trusted_cert/4, foldl/3, - lookup_cached_pem/2, cache_pem_file/2, cache_pem_file/3, - lookup/2]). - -%%==================================================================== -%% Internal application API -%%==================================================================== - -%%-------------------------------------------------------------------- --spec create() -> [db_handle(),...]. -%% -%% Description: Creates a new certificate db. -%% Note: lookup_trusted_cert/4 may be called from any process but only -%% the process that called create may call the other functions. -%%-------------------------------------------------------------------- -create() -> - [%% Let connection process delete trusted certs - %% that can only belong to one connection. (Supplied directly - %% on DER format to ssl:connect/listen.) - ets:new(ssl_otp_cacertificate_db, [set, public]), - %% Let connection processes call ref_count/3 directly - ets:new(ssl_otp_ca_file_ref, [set, public]), - ets:new(ssl_otp_pem_cache, [set, protected]) - ]. - -%%-------------------------------------------------------------------- --spec remove([db_handle()]) -> ok. -%% -%% Description: Removes database db -%%-------------------------------------------------------------------- -remove(Dbs) -> - lists:foreach(fun(Db) -> - true = ets:delete(Db) - end, Dbs). - -%%-------------------------------------------------------------------- --spec lookup_trusted_cert(db_handle(), certdb_ref(), serialnumber(), issuer()) -> - undefined | {ok, {der_cert(), #'OTPCertificate'{}}}. - -%% -%% Description: Retrives the trusted certificate identified by -%% . Ref is used as it is specified -%% for each connection which certificates are trusted. -%%-------------------------------------------------------------------- -lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) -> - case lookup({Ref, SerialNumber, Issuer}, DbHandle) of - undefined -> - undefined; - [Certs] -> - {ok, Certs} - end. - -lookup_cached_pem([_, _, PemChache], MD5) -> - lookup_cached_pem(PemChache, MD5); -lookup_cached_pem(PemChache, MD5) -> - lookup(MD5, PemChache). - -%%-------------------------------------------------------------------- --spec add_trusted_certs(pid(), {erlang:timestamp(), string()} | - {der, list()}, [db_handle()]) -> {ok, [db_handle()]}. -%% -%% Description: Adds the trusted certificates from file to the -%% runtime database. Returns Ref that should be handed to lookup_trusted_cert -%% together with the cert serialnumber and issuer. -%%-------------------------------------------------------------------- -add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) -> - NewRef = make_ref(), - add_certs_from_der(DerList, NewRef, CerDb), - {ok, NewRef}; - -add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) -> - MD5 = crypto:hash(md5, File), - case lookup_cached_pem(Db, MD5) of - [{_Content, Ref}] -> - ref_count(Ref, RefDb, 1), - {ok, Ref}; - [Content] -> - Ref = make_ref(), - update_counter(Ref, 1, RefDb), - insert(MD5, {Content, Ref}, PemChache), - add_certs_from_pem(Content, Ref, CertsDb), - {ok, Ref}; - undefined -> - new_trusted_cert_entry({MD5, File}, Db) - end. -%%-------------------------------------------------------------------- --spec cache_pem_file({binary(), binary()}, [db_handle()]) -> {ok, term()}. --spec cache_pem_file(reference(), {binary(), binary()}, [db_handle()]) -> {ok, term()}. -%% -%% Description: Cache file as binary in DB -%%-------------------------------------------------------------------- -cache_pem_file({MD5, File}, [_CertsDb, _RefDb, PemChache]) -> - {ok, PemBin} = file:read_file(File), - Content = public_key:pem_decode(PemBin), - insert(MD5, Content, PemChache), - {ok, Content}. - -cache_pem_file(Ref, {MD5, File}, [_CertsDb, _RefDb, PemChache]) -> - {ok, PemBin} = file:read_file(File), - Content = public_key:pem_decode(PemBin), - insert(MD5, {Content, Ref}, PemChache), - {ok, Content}. - -%%-------------------------------------------------------------------- --spec remove_trusted_certs(reference(), db_handle()) -> ok. -%% -%% Description: Removes all trusted certificates refernced by . -%%-------------------------------------------------------------------- -remove_trusted_certs(Ref, CertsDb) -> - remove_certs(Ref, CertsDb). - -%%-------------------------------------------------------------------- --spec remove(term(), db_handle()) -> ok. -%% -%% Description: Removes an element in a . -%%-------------------------------------------------------------------- -remove(Key, Db) -> - ets:delete(Db, Key), - ok. - -%%-------------------------------------------------------------------- --spec lookup(term(), db_handle()) -> [term()] | undefined. -%% -%% Description: Looks up an element in a . -%%-------------------------------------------------------------------- -lookup(Key, Db) -> - case ets:lookup(Db, Key) of - [] -> - undefined; - Contents -> - Pick = fun({_, Data}) -> Data; - ({_,_,Data}) -> Data - end, - [Pick(Data) || Data <- Contents] - end. -%%-------------------------------------------------------------------- --spec foldl(fun((_,_) -> term()), term(), db_handle()) -> term(). -%% -%% Description: Calls Fun(Elem, AccIn) on successive elements of the -%% cache, starting with AccIn == Acc0. Fun/2 must return a new -%% accumulator which is passed to the next call. The function returns -%% the final value of the accumulator. Acc0 is returned if the certifate -%% db is empty. -%%-------------------------------------------------------------------- -foldl(Fun, Acc0, Cache) -> - ets:foldl(Fun, Acc0, Cache). - -%%-------------------------------------------------------------------- --spec ref_count(term(), db_handle(), integer()) -> integer(). -%% -%% Description: Updates a reference counter in a . -%%-------------------------------------------------------------------- -ref_count(Key, Db, N) -> - ets:update_counter(Db,Key,N). - -%%-------------------------------------------------------------------- --spec clear(db_handle()) -> ok. -%% -%% Description: Clears the cache -%%-------------------------------------------------------------------- -clear(Db) -> - true = ets:delete_all_objects(Db), - ok. - -%%-------------------------------------------------------------------- --spec db_size(db_handle()) -> integer(). -%% -%% Description: Returns the size of the db -%%-------------------------------------------------------------------- -db_size(Db) -> - ets:info(Db, size). - -%%-------------------------------------------------------------------- --spec insert(Key::term(), Data::term(), Db::db_handle()) -> ok. -%% -%% Description: Inserts data into -%%-------------------------------------------------------------------- -insert(Key, Data, Db) -> - true = ets:insert(Db, {Key, Data}), - ok. - -%%-------------------------------------------------------------------- -%%% Internal functions -%%-------------------------------------------------------------------- -update_counter(Key, Count, Db) -> - true = ets:insert(Db, {Key, Count}), - ok. - -remove_certs(Ref, CertsDb) -> - true = ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}), - ok. - -add_certs_from_der(DerList, Ref, CertsDb) -> - Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end, - [Add(Cert) || Cert <- DerList], - ok. - -add_certs_from_pem(PemEntries, Ref, CertsDb) -> - Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end, - [Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries], - ok. - -add_certs(Cert, Ref, CertsDb) -> - try ErlCert = public_key:pkix_decode_cert(Cert, otp), - TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, - SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber, - Issuer = public_key:pkix_normalize_name( - TBSCertificate#'OTPTBSCertificate'.issuer), - insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb) - catch - error:_ -> - Report = io_lib:format("SSL WARNING: Ignoring a CA cert as " - "it could not be correctly decoded.~n", []), - error_logger:info_report(Report) - end. - -new_trusted_cert_entry(FileRef, [CertsDb, RefDb, _] = Db) -> - Ref = make_ref(), - update_counter(Ref, 1, RefDb), - {ok, Content} = cache_pem_file(Ref, FileRef, Db), - add_certs_from_pem(Content, Ref, CertsDb), - {ok, Ref}. diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index de9260fd8c..c751e7fe45 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -2976,14 +2976,14 @@ handle_trusted_certs_db(#state{cert_db_ref = Ref, ssl_options = #ssl_options{cacertfile = undefined}}) -> %% Certs provided as DER directly can not be shared %% with other connections and it is safe to delete them when the connection ends. - ssl_certificate_db:remove_trusted_certs(Ref, CertDb); + ssl_pkix_db:remove_trusted_certs(Ref, CertDb); handle_trusted_certs_db(#state{file_ref_db = undefined}) -> %% Something went wrong early (typically cacertfile does not exist) so there is nothing to handle ok; handle_trusted_certs_db(#state{cert_db_ref = Ref, file_ref_db = RefDb, ssl_options = #ssl_options{cacertfile = File}}) -> - case ssl_certificate_db:ref_count(Ref, RefDb, -1) of + case ssl_pkix_db:ref_count(Ref, RefDb, -1) of 0 -> ssl_manager:clean_cert_db(Ref, File); _ -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 24ea86311f..77c634616e 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1685,7 +1685,7 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) -> (_, Acc) -> Acc end, - ssl_certificate_db:foldl(ConnectionCerts, [], CertDbHandle). + ssl_pkix_db:foldl(ConnectionCerts, [], CertDbHandle). digitally_signed({3, Minor}, Hash, HashAlgo, Key) when Minor >= 3 -> diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index caea528a08..1b06e351cf 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -104,7 +104,8 @@ connection_init(Trustedcerts, Role) -> %%-------------------------------------------------------------------- cache_pem_file(File, DbHandle) -> MD5 = crypto:hash(md5, File), - case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of + MD5 = crypto:md5(File), + case ssl_pkix_db:lookup_cached_pem(DbHandle, MD5) of [{Content,_}] -> {ok, Content}; [Content] -> @@ -132,7 +133,7 @@ clear_pem_cache() -> %% serialnumber(), issuer()}. %% -------------------------------------------------------------------- lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) -> - ssl_certificate_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer). + ssl_pkix_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer). %%-------------------------------------------------------------------- -spec new_session_id(integer()) -> session_id(). @@ -194,7 +195,7 @@ init([Name, Opts]) -> CacheCb = proplists:get_value(session_cb, Opts, ssl_session_cache), SessionLifeTime = proplists:get_value(session_lifetime, Opts, ?'24H_in_sec'), - CertDb = ssl_certificate_db:create(), + CertDb = ssl_pkix_db:create(), SessionCache = CacheCb:init(proplists:get_value(session_cb_init_args, Opts, [])), Timer = erlang:send_after(SessionLifeTime * 1000 + 5000, self(), validate_sessions), @@ -227,7 +228,7 @@ handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From, session_cache = Cache} = State) -> Result = try - {ok, Ref} = ssl_certificate_db:add_trusted_certs(Pid, Trustedcerts, Db), + {ok, Ref} = ssl_pkix_db:add_trusted_certs(Pid, Trustedcerts, Db), {ok, Ref, CertDb, FileRefDb, PemChace, Cache} catch _:Reason -> @@ -244,7 +245,7 @@ handle_call({{new_session_id,Port}, _}, handle_call({{cache_pem, File}, _Pid}, _, #state{certificate_db = Db} = State) -> - try ssl_certificate_db:cache_pem_file(File, Db) of + try ssl_pkix_db:cache_pem_file(File, Db) of Result -> {reply, Result, State} catch @@ -252,7 +253,7 @@ handle_call({{cache_pem, File}, _Pid}, _, {reply, {error, Reason}, State} end; handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_,PemChace]} = State) -> - ssl_certificate_db:clear(PemChace), + ssl_pkix_db:clear(PemChace), {reply, ok, State}. %%-------------------------------------------------------------------- @@ -315,11 +316,11 @@ handle_info({delayed_clean_session, Key}, #state{session_cache = Cache, {noreply, State}; handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) -> - case ssl_certificate_db:db_size(PemChace) of + case ssl_pkix_db:db_size(PemChace) of N when N < ?NOT_TO_BIG -> ok; _ -> - ssl_certificate_db:clear(PemChace) + ssl_pkix_db:clear(PemChace) end, erlang:send_after(?CLEAR_PEM_CACHE, self(), clear_pem_cache), {noreply, State}; @@ -328,7 +329,7 @@ handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) -> handle_info({clean_cert_db, Ref, File}, #state{certificate_db = [CertDb,RefDb, PemCache]} = State) -> - case ssl_certificate_db:lookup(Ref, RefDb) of + case ssl_pkix_db:lookup(Ref, RefDb) of undefined -> %% Alredy cleaned ok; _ -> @@ -357,7 +358,7 @@ terminate(_Reason, #state{certificate_db = Db, session_cache_cb = CacheCb, session_validation_timer = Timer}) -> erlang:cancel_timer(Timer), - ssl_certificate_db:remove(Db), + ssl_pkix_db:remove(Db), CacheCb:terminate(SessionCache), ok. @@ -466,17 +467,17 @@ new_id(Port, Tries, Cache, CacheCb) -> end. clean_cert_db(Ref, CertDb, RefDb, PemCache, File) -> - case ssl_certificate_db:ref_count(Ref, RefDb, 0) of + case ssl_pkix_db:ref_count(Ref, RefDb, 0) of 0 -> MD5 = crypto:hash(md5, File), - case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of + case ssl_pkix_db:lookup_cached_pem(PemCache, MD5) of [{Content, Ref}] -> - ssl_certificate_db:insert(MD5, Content, PemCache); + ssl_pkix_db:insert(MD5, Content, PemCache); _ -> ok end, - ssl_certificate_db:remove(Ref, RefDb), - ssl_certificate_db:remove_trusted_certs(Ref, CertDb); + ssl_pkix_db:remove(Ref, RefDb), + ssl_pkix_db:remove_trusted_certs(Ref, CertDb); _ -> ok end. diff --git a/lib/ssl/src/ssl_pkix_db.erl b/lib/ssl/src/ssl_pkix_db.erl new file mode 100644 index 0000000000..9de50c8f26 --- /dev/null +++ b/lib/ssl/src/ssl_pkix_db.erl @@ -0,0 +1,253 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%---------------------------------------------------------------------- +%% Purpose: Storage for trusted certificates +%%---------------------------------------------------------------------- + +-module(ssl_pkix_db). + +-include("ssl_internal.hrl"). +-include_lib("public_key/include/public_key.hrl"). +-include_lib("kernel/include/file.hrl"). + +-export([create/0, remove/1, add_trusted_certs/3, + remove_trusted_certs/2, insert/3, remove/2, clear/1, db_size/1, + ref_count/3, lookup_trusted_cert/4, foldl/3, + lookup_cached_pem/2, cache_pem_file/2, cache_pem_file/3, + lookup/2]). + +%%==================================================================== +%% Internal application API +%%==================================================================== + +%%-------------------------------------------------------------------- +-spec create() -> [db_handle(),...]. +%% +%% Description: Creates a new certificate db. +%% Note: lookup_trusted_cert/4 may be called from any process but only +%% the process that called create may call the other functions. +%%-------------------------------------------------------------------- +create() -> + [%% Let connection process delete trusted certs + %% that can only belong to one connection. (Supplied directly + %% on DER format to ssl:connect/listen.) + ets:new(ssl_otp_cacertificate_db, [set, public]), + %% Let connection processes call ref_count/3 directly + ets:new(ssl_otp_ca_file_ref, [set, public]), + ets:new(ssl_otp_pem_cache, [set, protected]) + ]. + +%%-------------------------------------------------------------------- +-spec remove([db_handle()]) -> ok. +%% +%% Description: Removes database db +%%-------------------------------------------------------------------- +remove(Dbs) -> + lists:foreach(fun(Db) -> + true = ets:delete(Db) + end, Dbs). + +%%-------------------------------------------------------------------- +-spec lookup_trusted_cert(db_handle(), certdb_ref(), serialnumber(), issuer()) -> + undefined | {ok, {der_cert(), #'OTPCertificate'{}}}. + +%% +%% Description: Retrives the trusted certificate identified by +%% . Ref is used as it is specified +%% for each connection which certificates are trusted. +%%-------------------------------------------------------------------- +lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) -> + case lookup({Ref, SerialNumber, Issuer}, DbHandle) of + undefined -> + undefined; + [Certs] -> + {ok, Certs} + end. + +lookup_cached_pem([_, _, PemChache], MD5) -> + lookup_cached_pem(PemChache, MD5); +lookup_cached_pem(PemChache, MD5) -> + lookup(MD5, PemChache). + +%%-------------------------------------------------------------------- +-spec add_trusted_certs(pid(), {erlang:timestamp(), string()} | + {der, list()}, [db_handle()]) -> {ok, [db_handle()]}. +%% +%% Description: Adds the trusted certificates from file to the +%% runtime database. Returns Ref that should be handed to lookup_trusted_cert +%% together with the cert serialnumber and issuer. +%%-------------------------------------------------------------------- +add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) -> + NewRef = make_ref(), + add_certs_from_der(DerList, NewRef, CerDb), + {ok, NewRef}; + +add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) -> + MD5 = crypto:hash(md5, File), + case lookup_cached_pem(Db, MD5) of + [{_Content, Ref}] -> + ref_count(Ref, RefDb, 1), + {ok, Ref}; + [Content] -> + Ref = make_ref(), + update_counter(Ref, 1, RefDb), + insert(MD5, {Content, Ref}, PemChache), + add_certs_from_pem(Content, Ref, CertsDb), + {ok, Ref}; + undefined -> + new_trusted_cert_entry({MD5, File}, Db) + end. +%%-------------------------------------------------------------------- +-spec cache_pem_file({binary(), binary()}, [db_handle()]) -> {ok, term()}. +-spec cache_pem_file(reference(), {binary(), binary()}, [db_handle()]) -> {ok, term()}. +%% +%% Description: Cache file as binary in DB +%%-------------------------------------------------------------------- +cache_pem_file({MD5, File}, [_CertsDb, _RefDb, PemChache]) -> + {ok, PemBin} = file:read_file(File), + Content = public_key:pem_decode(PemBin), + insert(MD5, Content, PemChache), + {ok, Content}. + +cache_pem_file(Ref, {MD5, File}, [_CertsDb, _RefDb, PemChache]) -> + {ok, PemBin} = file:read_file(File), + Content = public_key:pem_decode(PemBin), + insert(MD5, {Content, Ref}, PemChache), + {ok, Content}. + +%%-------------------------------------------------------------------- +-spec remove_trusted_certs(reference(), db_handle()) -> ok. +%% +%% Description: Removes all trusted certificates refernced by . +%%-------------------------------------------------------------------- +remove_trusted_certs(Ref, CertsDb) -> + remove_certs(Ref, CertsDb). + +%%-------------------------------------------------------------------- +-spec remove(term(), db_handle()) -> ok. +%% +%% Description: Removes an element in a . +%%-------------------------------------------------------------------- +remove(Key, Db) -> + ets:delete(Db, Key), + ok. + +%%-------------------------------------------------------------------- +-spec lookup(term(), db_handle()) -> [term()] | undefined. +%% +%% Description: Looks up an element in a . +%%-------------------------------------------------------------------- +lookup(Key, Db) -> + case ets:lookup(Db, Key) of + [] -> + undefined; + Contents -> + Pick = fun({_, Data}) -> Data; + ({_,_,Data}) -> Data + end, + [Pick(Data) || Data <- Contents] + end. +%%-------------------------------------------------------------------- +-spec foldl(fun((_,_) -> term()), term(), db_handle()) -> term(). +%% +%% Description: Calls Fun(Elem, AccIn) on successive elements of the +%% cache, starting with AccIn == Acc0. Fun/2 must return a new +%% accumulator which is passed to the next call. The function returns +%% the final value of the accumulator. Acc0 is returned if the certifate +%% db is empty. +%%-------------------------------------------------------------------- +foldl(Fun, Acc0, Cache) -> + ets:foldl(Fun, Acc0, Cache). + +%%-------------------------------------------------------------------- +-spec ref_count(term(), db_handle(), integer()) -> integer(). +%% +%% Description: Updates a reference counter in a . +%%-------------------------------------------------------------------- +ref_count(Key, Db, N) -> + ets:update_counter(Db,Key,N). + +%%-------------------------------------------------------------------- +-spec clear(db_handle()) -> ok. +%% +%% Description: Clears the cache +%%-------------------------------------------------------------------- +clear(Db) -> + true = ets:delete_all_objects(Db), + ok. + +%%-------------------------------------------------------------------- +-spec db_size(db_handle()) -> integer(). +%% +%% Description: Returns the size of the db +%%-------------------------------------------------------------------- +db_size(Db) -> + ets:info(Db, size). + +%%-------------------------------------------------------------------- +-spec insert(Key::term(), Data::term(), Db::db_handle()) -> ok. +%% +%% Description: Inserts data into +%%-------------------------------------------------------------------- +insert(Key, Data, Db) -> + true = ets:insert(Db, {Key, Data}), + ok. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +update_counter(Key, Count, Db) -> + true = ets:insert(Db, {Key, Count}), + ok. + +remove_certs(Ref, CertsDb) -> + true = ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}), + ok. + +add_certs_from_der(DerList, Ref, CertsDb) -> + Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end, + [Add(Cert) || Cert <- DerList], + ok. + +add_certs_from_pem(PemEntries, Ref, CertsDb) -> + Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end, + [Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries], + ok. + +add_certs(Cert, Ref, CertsDb) -> + try ErlCert = public_key:pkix_decode_cert(Cert, otp), + TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, + SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber, + Issuer = public_key:pkix_normalize_name( + TBSCertificate#'OTPTBSCertificate'.issuer), + insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb) + catch + error:_ -> + Report = io_lib:format("SSL WARNING: Ignoring a CA cert as " + "it could not be correctly decoded.~n", []), + error_logger:info_report(Report) + end. + +new_trusted_cert_entry(FileRef, [CertsDb, RefDb, _] = Db) -> + Ref = make_ref(), + update_counter(Ref, 1, RefDb), + {ok, Content} = cache_pem_file(Ref, FileRef, Db), + add_certs_from_pem(Content, Ref, CertsDb), + {ok, Ref}. -- cgit v1.2.3