Skip to content

Commit

Permalink
Merge pull request #8 from grisp/sylane/tls-helper
Browse files Browse the repository at this point in the history
Add basic emulation, TLS config helper and general cleanup.
  • Loading branch information
sylane authored Jul 29, 2024
2 parents 11fdab5 + 2f87dd7 commit 3cf3130
Show file tree
Hide file tree
Showing 15 changed files with 567 additions and 90 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ _build
*.o
_checkouts
_grisp
.tool-versions
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ and this project adheres to

## [Unreleased]

- Add grisp_cryptoauth_tls, an helper to generate TLS options for connecting
to servers with client certificate authentication driven by grisp_cryptoauth
configuration

- Add EMULATE_CRYPTOAUTH macro that could be defined for grisp_cryptoauth to
be used in tests and in local shell.

## [2.3.0] - 2024-06-27

- Add sign_fun/3 to support OTP 27 new key option for secure Elements
Expand Down
171 changes: 169 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ with cryptoauthlib installed, build within the `grisp_linux_builder`.
Just add it as dependency in rebar3 in your main application.


Development
-----------

When included as a dependency in an application, is is possible to define
the macro ENUMATE_CRYPTOAUTH using overrides:

{overrides, [
{add, grisp_cryptoauth, [{erl_opts, [{d, 'EMULATE_CRYPTOAUTH'}]}]}
]},

With this defined, the extra configuration keys `client_cert`, `client_key` and
`tls_verify` can be specified to be used instead of the secure element.

This allow an application depending on grisp_cryptoauth to run tests and local
shell.


Device Support
--------------

Expand All @@ -34,8 +51,158 @@ This library follows the ATECC608B-TFLXTLS configuration, that means in particul
More to come :).


Setting up TLS
--------------
Configuring TLS Options
-----------------------

By configuring grisp_cryptoauth, multiple application can request the TLS
options required to connect to a given server, assuming that all the servers
have the same security requirments. The following options are used to build
the TLS options:


* `tls_use_client_certificate`

Configures if TLS cponnections should use the client certificate. Default: true.


* `tls_client_trusted_certs`

Configures the client trusted certificates.

Should provide all the additional certificates required to validate to the
client root CA, alongside the `tls_client_trusted_certs_cb` option.

Point to a directory from where all the `.pem` and `.crt` files will be loaded,
or to a single PEM file that could contain multiple certificates.

The configuration could either be an absolute path, a path relative to the
`priv` directory of a given application, or a path relative to an application
`test` directory.

If not specified, it will use the default certificate chain matching the
client certificate.

e.g.

```Erlang
{tls_client_trusted_certs, "/absolute/path/to/directory"}
{tls_client_trusted_certs, "/absolute/path/to/single.pem"}
{tls_client_trusted_certs, {priv, my_app, "relative/path/to/directory"}}
{tls_client_trusted_certs, {priv, my_app, "relative/path/to/single.pem"}}
{tls_client_trusted_certs, {test, my_app, "relative/path/to/directory"}}
{tls_client_trusted_certs, {test, my_app, "relative/path/to/single.pem"}}
```

* `tls_client_trusted_certs_cb`

Configures the client trusted certificates.

Should provide all the additional certificates required to validate to the
client root CA, alongside the `tls_client_trusted_certs` option.

Define a callback function the will return the client trusted certificates
as a list of DER encoded certificates.

e.g.

```Erlang
{tls_client_trusted_certs_cb, {my_mod, my_fun}}}
{tls_client_trusted_certs_cb, {my_mod, my_fun, [some, arguments]}}}
```

* `tls_server_trusted_certs`

Configures the server trusted certificates.

Should provide the certification chain for veryfying the server certificates,
alongside the `tls_server_trusted_certs_cb` option.

Point to a directory that should contain a PEM file with extension `.pem`
or `.crt` with the name of the domain the TLS connection is for. If multiple
certificates are required, the file must contain the full chain.
If the path is set to `/foo/bar`, and the server doain name is `grisp.org`,
the TLS configuration will try the certificate `/foo/bar/grisp.org.pem` or
`/foo/bar/grisp.org.crt` if any exists.

The configuration could either be an absolute path, a path relative to the
`priv` directory of a given application, or a path relative to an application
`test` directory.

e.g.

```Erlang
{tls_server_trusted_certs, "/absolute/path/to/directory"}
{tls_server_trusted_certs, {priv, my_app, "relative/path/to/directory"}}
{tls_server_trusted_certs, {test, my_app, "relative/path/to/directory"}}
```

* `tls_server_trusted_certs_cb`

Configures the server trusted certificates.

Should provide the certification chain for veryfying the server certificates,
alongside the `tls_server_trusted_certs` option.

Define a callback function the will return the client trusted certificates
as a list of DER encoded certificates.

e.g.

```Erlang
{tls_server_trusted_certs_cb, {certifi, cacerts}}}
{tls_server_trusted_certs_cb, {my_mod, my_fun, [some, arguments]}}}
```

* `client_certs`

When EMULATE_CRYPTOAUTH macro is defined, this configures the certificate to
use instead of the secure element's one when generating TLS options.

The configuration could either be an absolute path, a path relative to the
`priv` directory of a given application, or a path relative to an application
`test` directory.

e.g.

```Erlang
{client_certs, "/absolute/path/to/some.pem"}
{client_certs, {priv, my_app, "relative/path/to/some.crt"}}
{client_certs, {test, my_app, "relative/cert.pem"}}
```

* `client_key`

When EMULATE_CRYPTOAUTH macro is defined, this configures the private key to
use instead of the secure element's one when generating TLS options.

The configuration could either be an absolute path, a path relative to the
`priv` directory of a given application, or a path relative to an application
`test` directory.

e.g.

```Erlang
{client_key, "/absolute/path/to/some.pem"}
{client_key, {priv, my_app, "relative/path/to/some.key"}}
{client_key, {test, my_app, "relative/key.pem"}}
```

* `tls_verify`

When EMULATE_CRYPTOAUTH macro is defined, this allow overriding server
certificate verification for development or testing. By default it is
`verify_peer` but can be set to `verify_none`.

e.g.

```Erlang
{tls_verify, verify_none}
```


Setting Up TLS Manually
-----------------------

Erlang's `ssl` library is used for setting up TLS/mTLS. For the device
you need to honor at least the following options:
#### OTP >= 27
Expand Down
47 changes: 47 additions & 0 deletions config/sys.config
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,51 @@
{{1, 0}, grisp2_intermediate},
{{2, 0}, grisp2_device}
]}

%% Configuration for TLS option generation:

%% Define if client certificate should be used for TLS, true if not specified.
% {tls_use_client_certificate, true},

%% Configure trusted certificates for verification of the client
%% certificate with files. Can be a path to a PEM file, to a directory
%% containing multiple PEM files, or a callback function specification.
% {tls_client_trusted_certs, "/absolute/path/to/directory"},
% {tls_client_trusted_certs, "/absolute/path/to/single.pem"},
% {tls_client_trusted_certs, {priv, MyApp, "relative/path/to/directory"}},
% {tls_client_trusted_certs, {priv, MyApp, "relative/path/to/single.pem"}},
% {tls_client_trusted_certs, {test, MyApp, "relative/path/to/directory"}},
% {tls_client_trusted_certs, {test, MyApp, "relative/path/to/single.pem"}},

%% Configure the trusted certificates for verification of the client
%% certificate with callback. If not specified, the callback do not take any
%% arguments.
% {tls_client_trusted_certs_cb, {ModName, FunName}},
% {tls_client_trusted_certs_cb, {ModName, FunName, FunArgs}},

%% Configure trusted certificates for verification of the server certificate
%% with files. Define a directory that contains server certificate for TLS
%% verification. Can be an absolute path, or a tuple with an application name
%% and a relative path from the app root directory.
%% The directory should contains PEM files with the server domain name and the
%% '.pem' extension.
% {tls_server_trusted_certs, "/etc/servers"},
% {tls_server_trusted_certs, {priv, MyApp, "servers"}},
% {tls_server_trusted_certs, {test, MyApp, "certs"}},

%% Configure trusted certificates for verification of the server certificate
%% with callback. If not specified, the callback do not take any
%% arguments.
% {tls_server_trusted_certs_cb, {ModName, FunName}},
% {tls_server_trusted_certs_cb, {ModName, FunName, FunArgs}},

%% Configuration for emulation, if EMULATE_CRYPTOAUTH is defined:

%% The client certificate and private key to use instead of the secure element.
%% The values can be either an absolute path or tuple of an app name and
%% a relative path to the root of the given app.
% {client_certs, {MyApp, "priv/client_cert.pem"}},
% {client_key, {MyApp, "priv/client_key.pem"}},
%% Can be set to verify_none to disable server certificate verification.
% {tls_verify, verify_peer}
]}].
13 changes: 0 additions & 13 deletions priv/cert_test/README.md

This file was deleted.

11 changes: 0 additions & 11 deletions priv/cert_test/example_client_cert.pem

This file was deleted.

13 changes: 0 additions & 13 deletions priv/cert_test/intermediate_cert.pem

This file was deleted.

5 changes: 0 additions & 5 deletions priv/cert_test/intermediate_private.pem

This file was deleted.

12 changes: 0 additions & 12 deletions priv/cert_test/root_cert.pem

This file was deleted.

7 changes: 0 additions & 7 deletions priv/cert_test/root_private.pem

This file was deleted.

7 changes: 6 additions & 1 deletion src/grisp_cryptoauth.erl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@
i2c_address => 16#6C}).

-define(API_SERVER, grisp_cryptoauth_api_server).
-define(CALL_API_SERVER(Args), gen_server:call(?API_SERVER, {?FUNCTION_NAME, Args})).
-define(CALL_API_SERVER(Args),
case gen_server:call(?API_SERVER, {?FUNCTION_NAME, Args}) of
{ok, Result} -> Result;
{error, Class, Reason, Stacktrace} ->
erlang:raise(Class, Reason, Stacktrace)
end).

%% ---------------
%% Main API
Expand Down
7 changes: 5 additions & 2 deletions src/grisp_cryptoauth_api_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ handle_call({Fun, Args}, _From, {Context, OldTRef}) ->
%% to sleep after SLEEP_TIME_SEC seconds to save energy
timer:cancel(OldTRef), %% this doesn't throw on bad args
{ok, NewTRef} = timer:apply_after(?SLEEP_TIME_SEC * 1000, grisp_cryptoauth, sleep, [Context]),
{reply, apply(grisp_cryptoauth, Fun, [Context | Args]), {Context, NewTRef}}.

try apply(grisp_cryptoauth, Fun, [Context | Args]) of
Result -> {reply, {ok, Result}, {Context, NewTRef}}
catch
C:R:S -> {reply, {error, C, R, S}, {Context, NewTRef}}
end.

handle_cast(_, State) ->
{noreply, State}.
6 changes: 0 additions & 6 deletions src/grisp_cryptoauth_app.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@


start(_StartType, _StartArgs) ->
%% Only successful for GRiSP2 builds,
%% meant to setup I2C bus through the
%% GRiSP platform, otherwise the
%% standard Linux bus driver is used.
application:ensure_all_started(grisp),
grisp_cryptoauth_sup:start_link().


stop(_State) ->
ok.
Loading

0 comments on commit 3cf3130

Please sign in to comment.