laforge has submitted this change. ( https://gerrit.osmocom.org/c/onomondo-eim/+/42830?usp=email )
Change subject: certificates: fix certificate location, make sure cert/key files are readable ......................................................................
certificates: fix certificate location, make sure cert/key files are readable
The certificate and key files are placed in the config directory. This is an unfortunate location, since it causes a lot of trouble when referencing those files.
The erlang documentation suggests to place so called auxillary files in a "priv" directory on the same level as the config directory. The path to the priv directory can then be located using code:priv_dir.
see also: https://www.erlang.org/docs/26/design_principles/applications.html
Let's adopt this mechanism by adding utility functions that allow us to resolve the file paths to files inside the priv directory. Let's also automatically check if the referenced file is readable, so that we get a proper error in the log in case a certificate or key file is missing
Change-Id: Ie09d746a6e28ac6fee3e00dfa32cb01f8a7b947e Related: SYS#7093 --- M config/sys.config R priv/sample_eim_cert_brainpool.crt R priv/sample_eim_cert_brainpool.key R priv/sample_eim_cert_nist.crt R priv/sample_eim_cert_nist.key R priv/sample_ssl_cert.crt R priv/sample_ssl_cert.key R priv/sgp26_gsma_root_ci_cert_nist_oiste.crt R priv/sgp26_gsma_root_ci_cert_nist_symantec.crt R priv/sgp26_test_root_ci_cert_brainpool.crt R priv/sgp26_test_root_ci_cert_nist.crt M src/crypto_utils.erl M src/eim_cfg.erl M src/onomondo_eim_app.erl M src/rest_handler.erl M src/utils.erl 16 files changed, 44 insertions(+), 22 deletions(-)
Approvals: fixeria: Looks good to me, but someone else must approve laforge: Looks good to me, approved Jenkins Builder: Verified
diff --git a/config/sys.config b/config/sys.config index 990a442..81c438c 100644 --- a/config/sys.config +++ b/config/sys.config @@ -3,24 +3,24 @@ {esipa_ip, {127, 0, 0, 1}}, {esipa_port, 8000}, {esipa_ssl_disable, false}, - {esipa_ssl_cert, "config/sample_ssl_cert.crt"}, - {esipa_ssl_key, "config/sample_ssl_cert.key"}, + {esipa_ssl_cert, "sample_ssl_cert.crt"}, + {esipa_ssl_key, "sample_ssl_cert.key"}, {rest_ip, {127, 0, 0, 1}}, {rest_port, 8080}, {eim_id, "eIM"}, {es9p_ssl_disable, false}, - {eim_cert, "config/sample_eim_cert_nist.crt"}, - {eim_key, "config/sample_eim_cert_nist.key"}, + {eim_cert, "sample_eim_cert_nist.crt"}, + {eim_key, "sample_eim_cert_nist.key"}, {counter_value, 1}, {consumer_euicc, true}, {rest_timeout_stuck, 300}, {rest_timeout_noshow, 1800}, {rest_timeout_expired, 86400}, {root_ci_certs, [ - "config/sgp26_gsma_root_ci_cert_nist_symantec.crt", - "config/sgp26_gsma_root_ci_cert_nist_oiste.crt", - "config/sgp26_test_root_ci_cert_nist.crt", - "config/sgp26_test_root_ci_cert_brainpool.crt" + "sgp26_gsma_root_ci_cert_nist_symantec.crt", + "sgp26_gsma_root_ci_cert_nist_oiste.crt", + "sgp26_test_root_ci_cert_nist.crt", + "sgp26_test_root_ci_cert_brainpool.crt" ]} ]} ]. diff --git a/config/sample_eim_cert_brainpool.crt b/priv/sample_eim_cert_brainpool.crt similarity index 100% rename from config/sample_eim_cert_brainpool.crt rename to priv/sample_eim_cert_brainpool.crt diff --git a/config/sample_eim_cert_brainpool.key b/priv/sample_eim_cert_brainpool.key similarity index 100% rename from config/sample_eim_cert_brainpool.key rename to priv/sample_eim_cert_brainpool.key diff --git a/config/sample_eim_cert_nist.crt b/priv/sample_eim_cert_nist.crt similarity index 100% rename from config/sample_eim_cert_nist.crt rename to priv/sample_eim_cert_nist.crt diff --git a/config/sample_eim_cert_nist.key b/priv/sample_eim_cert_nist.key similarity index 100% rename from config/sample_eim_cert_nist.key rename to priv/sample_eim_cert_nist.key diff --git a/config/sample_ssl_cert.crt b/priv/sample_ssl_cert.crt similarity index 100% rename from config/sample_ssl_cert.crt rename to priv/sample_ssl_cert.crt diff --git a/config/sample_ssl_cert.key b/priv/sample_ssl_cert.key similarity index 100% rename from config/sample_ssl_cert.key rename to priv/sample_ssl_cert.key diff --git a/config/sgp26_gsma_root_ci_cert_nist_oiste.crt b/priv/sgp26_gsma_root_ci_cert_nist_oiste.crt similarity index 100% rename from config/sgp26_gsma_root_ci_cert_nist_oiste.crt rename to priv/sgp26_gsma_root_ci_cert_nist_oiste.crt diff --git a/config/sgp26_gsma_root_ci_cert_nist_symantec.crt b/priv/sgp26_gsma_root_ci_cert_nist_symantec.crt similarity index 100% rename from config/sgp26_gsma_root_ci_cert_nist_symantec.crt rename to priv/sgp26_gsma_root_ci_cert_nist_symantec.crt diff --git a/config/sgp26_test_root_ci_cert_brainpool.crt b/priv/sgp26_test_root_ci_cert_brainpool.crt similarity index 100% rename from config/sgp26_test_root_ci_cert_brainpool.crt rename to priv/sgp26_test_root_ci_cert_brainpool.crt diff --git a/config/sgp26_test_root_ci_cert_nist.crt b/priv/sgp26_test_root_ci_cert_nist.crt similarity index 100% rename from config/sgp26_test_root_ci_cert_nist.crt rename to priv/sgp26_test_root_ci_cert_nist.crt diff --git a/src/crypto_utils.erl b/src/crypto_utils.erl index 9d0cd0f..aca40e9 100644 --- a/src/crypto_utils.erl +++ b/src/crypto_utils.erl @@ -51,7 +51,7 @@ ]),
%Load private key from eIM certificate - {ok, EimKeyPath} = application:get_env(onomondo_eim, eim_key), + {ok, EimKeyPath} = utils:get_env_priv_file_path(onomondo_eim, eim_key), {ok, EimKeyPem} = file:read_file(EimKeyPath), [EimKeyPemEntry] = public_key:pem_decode(EimKeyPem), EimKeyECPrivateKey = public_key:pem_entry_decode(EimKeyPemEntry), @@ -209,8 +209,9 @@ ] ), error; -get_root_cert(EumCertificate, RootCiCertPaths) -> - [RootCiCertPath | RootCiCertPathsTail] = RootCiCertPaths, +get_root_cert(EumCertificate, RootCiCerts) -> + [RootCiCert | RootCiCertsTail] = RootCiCerts, + {ok, RootCiCertPath} = utils:get_priv_file_path(onomondo_eim, RootCiCert), {ok, RootCiCertPem} = file:read_file(RootCiCertPath), [{'Certificate', RootCiCertBer, not_encrypted}] = public_key:pem_decode(RootCiCertPem), {ok, EumCertificateBer} = 'PKIX1Explicit88':encode('Certificate', EumCertificate), @@ -218,12 +219,12 @@ true -> {ok, RootCiCertPem}; _ -> - get_root_cert(EumCertificate, RootCiCertPathsTail) + get_root_cert(EumCertificate, RootCiCertsTail) end.
verify_euicc_cert(EumCertificate, EuiccCertificate) -> - {ok, RootCiCertPaths} = application:get_env(onomondo_eim, root_ci_certs), - case get_root_cert(EumCertificate, RootCiCertPaths) of + {ok, RootCiCerts} = application:get_env(onomondo_eim, root_ci_certs), + case get_root_cert(EumCertificate, RootCiCerts) of {ok, RootCiCertPem} -> [{'Certificate', RootCiCertBer, not_encrypted}] = public_key:pem_decode(RootCiCertPem), {ok, RootCiCert} = 'PKIX1Explicit88':decode('Certificate', RootCiCertBer), diff --git a/src/eim_cfg.erl b/src/eim_cfg.erl index 6872461..f74ccd8 100644 --- a/src/eim_cfg.erl +++ b/src/eim_cfg.erl @@ -13,7 +13,7 @@ {ok, EimId} = application:get_env(onomondo_eim, eim_id), {ok, EsipaIp} = application:get_env(onomondo_eim, esipa_ip), {ok, EsipaPort} = application:get_env(onomondo_eim, esipa_port), - {ok, EimCertPath} = application:get_env(onomondo_eim, eim_cert), + {ok, EimCertPath} = utils:get_env_priv_file_path(onomondo_eim, eim_cert), {ok, EimCertPem} = file:read_file(EimCertPath), [{'Certificate', EimCertBer, not_encrypted}] = public_key:pem_decode(EimCertPem), {ok, EimCert} = 'PKIX1Explicit88':decode('Certificate', EimCertBer), diff --git a/src/onomondo_eim_app.erl b/src/onomondo_eim_app.erl index 5394ef5..97ed197 100644 --- a/src/onomondo_eim_app.erl +++ b/src/onomondo_eim_app.erl @@ -30,6 +30,7 @@ "Starting ESipa HTTPs server at ~p:~p...~ncertificate: ~p~nkey: ~p~n", [Ip, Port, Cert, Key] ), + cowboy:start_tls( https_listener_esipa, [ @@ -104,8 +105,8 @@ {ok, EsipaIp} = application:get_env(onomondo_eim, esipa_ip), {ok, EsipaPort} = application:get_env(onomondo_eim, esipa_port), {ok, EsipaSslDisable} = application:get_env(onomondo_eim, esipa_ssl_disable), - {ok, EsipaSslCert} = application:get_env(onomondo_eim, esipa_ssl_cert), - {ok, EsipaSslKey} = application:get_env(onomondo_eim, esipa_ssl_key), + {ok, EsipaSslCert} = utils:get_env_priv_file_path(onomondo_eim, esipa_ssl_cert), + {ok, EsipaSslKey} = utils:get_env_priv_file_path(onomondo_eim, esipa_ssl_key), {ok, _} = start_esipa_server( EsipaSslDisable, EsipaIp, diff --git a/src/rest_handler.erl b/src/rest_handler.erl index e4a24e9..db3f048 100644 --- a/src/rest_handler.erl +++ b/src/rest_handler.erl @@ -167,18 +167,19 @@ {ok, EsipaPort} = application:get_env(onomondo_eim, esipa_port), {ok, Hostname} = inet:gethostname(), {ok, Vsn} = application:get_key(onomondo_eim, vsn), - {ok, EsipaSslCertPath} = application:get_env(onomondo_eim, esipa_ssl_cert), + {ok, EsipaSslCertPath} = utils:get_env_priv_file_path(onomondo_eim, esipa_ssl_cert), {ok, EsipaSslCertPem} = file:read_file(EsipaSslCertPath), - {ok, EimCertPath} = application:get_env(onomondo_eim, eim_cert), + {ok, EimCertPath} = utils:get_env_priv_file_path(onomondo_eim, eim_cert), {ok, EimCertPem} = file:read_file(EimCertPath), {ok, CounterValue} = application:get_env(onomondo_eim, counter_value), {ok, ConsumerEuicc} = application:get_env(onomondo_eim, consumer_euicc), - FormatRootCiCert = fun(RootCiCertPath) -> + FormatRootCiCert = fun(RootCiCert) -> + {ok, RootCiCertPath} = utils:get_priv_file_path(onomondo_eim, RootCiCert), {ok, RootCiCertPem} = file:read_file(RootCiCertPath), RootCiCertPem end, {ok, RootCiCerts} = application:get_env(onomondo_eim, root_ci_certs), - RootCiCertsJson = [FormatRootCiCert(RootCiCertPath) || RootCiCertPath <- RootCiCerts], + RootCiCertsJson = [FormatRootCiCert(RootCiCert) || RootCiCert <- RootCiCerts],
InfoList = {[ diff --git a/src/utils.erl b/src/utils.erl index a71395b..d46dc2a 100644 --- a/src/utils.erl +++ b/src/utils.erl @@ -5,7 +5,8 @@ % Author: Philipp Maier pmaier@sysmocom.de / sysmocom - s.f.m.c. GmbH
-module(utils). --export([binary_to_hex/1, hex_to_binary/1, join_binary_list/1, integer_to_bytes/1, lpad_binary/3]). +-export([binary_to_hex/1, hex_to_binary/1, join_binary_list/1, integer_to_bytes/1, lpad_binary/3, + get_priv_file_path/2, get_env_priv_file_path/2]).
% Converts a single hex digit (e.g. <<"A">>) into its integer representation. hexstr_digit_to_int(HexDigit) -> @@ -87,3 +88,21 @@ BinaryPadded = <<Padding/binary, Binary/binary>>, lpad_binary(BinaryPadded, Padding, Length) end. + +% Get the full path for a file (from filename) located in the priv directory, make sure that the file is readable. +get_priv_file_path(Application, Filename) -> + PrivDir = code:priv_dir(Application), + FilePath = filename:join(PrivDir, Filename), + case filelib:is_file(FilePath) of + true -> + {ok, FilePath}; + _ -> + logger:error("file not found: ~s~n", [FilePath]), + error + end. + +% Get the full path for a file (from filename in sys.config environment variable) located in the priv directory, +% make sure that the file is readable. +get_env_priv_file_path(Application, Par) -> + {ok, Filename} = application:get_env(Application, Par), + get_priv_file_path(Application, Filename).