1# uOSCORE / uEDHOC
2
3![GitHub CI](https://github.com/eriptic/uoscore-uedhoc/actions/workflows/ci.yml/badge.svg)
4
5
6This repository contains C implementations  for constrained (and non-constrained) devices of the IETF protocols:
7
8* [OSOCRE (RFC8613)](https://tools.ietf.org/html/rfc8613) and
9* [EDHOC (draft-ietf-lake-edhoc-15 )](https://datatracker.ietf.org/doc/html/draft-ietf-lake-edhoc-15).
10
11Main features of uOSCORE and uEDHOC are their independence from the OS, cryptographic engine and in the case of uEDHOC transport protocol. Additionally,  uOSCORE and uEDHOC use only stack memory (no heap).
12
13For more background and evaluation in terms of speed, RAM and flash requirements see our paper [The Cost of OSCORE and EDHOC for Constrained Devices](https://arxiv.org/pdf/2103.13832.pdf).
14
15## How to Build and Link
16
17* check the configurations in `makefile_config.mk` and adjust them if necessary
18* run `make`
19* link the static library `build/libuoscore-uedhoc.a` in your project
20
21## Test coverage
22* [Test coverage report uOSCORE](https://eriptic.github.io/uoscore-uedhoc/src/oscore/index.html)
23* [Test coverage report uEDHOC](https://eriptic.github.io/uoscore-uedhoc/src/edhoc/index.html)
24
25## Project (Folder) Structure
26
27```
28.
29|---cddl_models/
30|---externals/
31|---inc/
32|---samples/
33|---scripts/
34|---src/
35|---test/
36|---test_vectors/
37```
38* The folder `cddl_models` contains CDDL models for all CBOR structures.
39* The folder `externals` contains the external libraries and tools as git submodules.
40* The folder `inc` contains all header file.
41* The folder `samples` contains some usage examples.
42* The folder `scripts` contains scripts for generatinc C code from CDDL models and converting the json formatted EDHOC test vectors to a C header
43* The folder `src` contains all source file.
44* The folder `test` contains automated tests.
45* The folder `test_vectors` contains tests vectors.
46
47## API and Usage Model
48
49#### uOSCORE
50
51The API of uOSCORE consists of three functions:
52* `oscore_context_init()`,
53*  `coap2oscore()` and
54*  `oscore2coap()`.
55
56`coap2oscore()` and `oscore2coap()` convert CoAP to OSCORE packets and vice versa. `oscore_context_init()` initializes the OSCORE security context.
57
58First, `oscore_context_init()` function needs to be called on the client and server side, then `coap2oscore()` and `oscore2coap()`  are called just before sending or receiving packets over the network.
59
60<img src="oscore_usage.svg" alt="drawing" width="600"/>
61
62
63#### uEDHOC
64
65The API of uEDHOC consists of four functions:
66*  `ephemeral_dh_key_gen()`
67* `edhoc_initiator_run()`,
68* `edhoc_responder_run()`,
69* `edhoc_exporter()`,
70
71`ephemeral_dh_key_gen()` is used to generate fresh ephemeral DH keys before running the protocol. This function requires a random seed suable for cryptographic purposes. `edhoc_initiator_run()` and `edhoc_responder_run() ` has to be called on the initiator and responder side respectively. They return the External Authorization data `EAD_x`,  the derived shared secret `PRK_out`.   `PRK_out` is used as input for `edhoc_exporter()` to derive application specific keys, e.g., OSCORE master secret and OSCORE master salt.
72
73The EDHOC protocol requires the exchange of three messages (and an optional message 4) which is independent of the underlying message transport protocol. For example [appendix-A.2 in the EDHOC specification](https://datatracker.ietf.org/doc/html/draft-ietf-lake-edhoc-15#appendix-A.2) describes how  EDHOC can be transferred over CoAP, however CoAP is not mandatory. In order to be independent of the transport protocol uEDHOC uses two callback functions which need to be implemented by the user for handling the sending and receiving of messages. These functions are:
74
75```c
76/**
77 * @brief   The user should call inside this function its send function.
78 *
79 *
80 * @param   sock a pointer used to identify the rx chanel,
81 *          e.g. a socket handler
82 * @param   data pointer to the data to be send
83 * @param   data_len length of the data
84 */
85enum err tx(void *sock, uint8_t *data, uint32_t data_len);
86
87/**
88 * @brief   The user should call inside this function its receive
89 *          function and copy the received data in the buffer <data>.
90 *          The length of the buffer <data> must be
91 *          checked before copying into it by using <data_len>.
92 *          After copying the length of the received data should be written
93 *          in <data_len>.
94 *
95 *
96 * @param   sock a pointer used to identify the rx chanel,
97 *          e.g. a socket handler
98 * @param   data pointer to a buffer where the edhoc message must be copied
99 * @param   data_len length of the received data. When this function is
100 *          called inside EDHOC <data_len> is initialized with the actual
101 *          available length of the <data>.
102 */
103enum err rx(void *sock, uint8_t *data, uint32_t *data_len);
104```
105
106Note that uEDHOC does not provide correlation of messages. Correlation may be handled on the transport layer completely or partially. In cases when the correlation cannot be handled by the transport protocol the edhoc message needs to be prepended with a connection identifier, that is used on the other side to determine to which session a given message belongs. In order to remain conform with the specification in the cases where the transport cannot handle correlation a connection identifier needs to be prepended in `tx()` function and removed in the `rx()` function.
107
108
109## Supported Cipher Suites
110
111##### uOSCORE
112
113| Algorithms                  |
114| --------------------------- |
115| AES-CCM-16-64-128,  SHA-256 |
116
117##### uEDHOC
118
119
120| Suit | Algorithms                                                                 |
121| ---- | -------------------------------------------------------------------------- |
122| 0    | AES-CCM-16-64-128, SHA-256, 8, X25519, EdDSA, AES-CCM-16-64-128, SHA-256   |
123| 1    | AES-CCM-16-128-128, SHA-256, 16, X25519, EdDSA, AES-CCM-16-64-128, SHA-256 |
124| 2    | AES-CCM-16-64-128, SHA-256, 8, P-256, ES256, AES-CCM-16-64-128, SHA-256    |
125| 3    | AES-CCM-16-128-128, SHA-256, 16, P-256, ES256, AES-CCM-16-64-128, SHA-256  |
126
127
128
129
130## Using Different Cryptographic Libraries or Hardware Accelerators
131
132The logic of uOSCORE and uEDHOC is independent form the cryptographic library, i.e., the cryptographic library can easily be exchanged by the user. For that the user needs to provide implementations for the functions specified in `crypto_wrapper.c`.
133
134## Preventing Nonce Reuse Attacks in OSCORE
135
136AES keys should never be used more than once with a given nonce, see [RFC5084](https://datatracker.ietf.org/doc/html/rfc5084). In order to avoid this situation, the user has 2 options while creating context structure:
137- setting `fresh_master_secret_salt = true`, when given context is new (freshly obtained e.g. with EDHOC)
138- setting `fresh_master_secret_salt = false`, when the same context is used between reboots/reconnections. In this case, the user must enable Non-volatile Memory support (see `OSCORE_NVM_SUPPORT` in `makefile_config.mk`) and implement two functions that require access to NVM (see below).
139
140Note that using NVM support is independent of the parameter above. Although it is required for using the same context multiple times, it will also be utilized (if enabled) to store context obtained with EDHOC, enabling the user to reuse it after the reboot. This behaviour is useful in situations where multiple sessions need to be stored on a device, while at the same time being able to start a completely new session with EDHOC. When such feature is not needed, `OSCORE_NVM_SUPPORT` can be disabled so only fresh sessions are acceptable.
141
142   ```c
143   /**
144   * @brief When the same OSCORE master secret and salt are reused through
145   *        several reboots of the device, e.g., no fresh shared secret is
146   *        derived through EDHOC (or some other method) the Sender Sequence
147   *        Number MUST be stored periodically in NVM.
148   * @param nvm_key part of the context that is permitted to be used for identifying the right store slot in NVM.
149   * @param	ssn SSN to be written in NVM.
150   * @retval ok or error code if storing the SSN was not possible.
151   */
152   enum err nvm_write_ssn(const struct nvm_key_t *nvm_key, uint64_t ssn);
153
154   /**
155   * @brief When the same OSCORE master secret and salt are reused through
156   *        several reboots of the device, e.g., no fresh shared secret is
157   *        derived through EDHOC (or some other method) the Sender Sequence
158   *        Number MUST be restored from NVM at each reboot.
159   * @param nvm_key part of the context that is permitted to be used for identifying the right store slot in NVM.
160   * @param	ssn SSN to be read out from NVM.
161   * @retval ok or error code if the retrieving the SSN was not possible.
162   */
163   enum err nvm_read_ssn(const struct nvm_key_t *nvm_key, uint64_t *ssn);
164   ```
165
166## Additional configuration options
167Following preprocessor directives allow for better memory usage adjustments:
168
169* **edhoc.h**
170
171   * EDHOC_BUF_SIZES_RPK - select when authentication can be based on raw public keys, or
172   * EDHOC_BUF_SIZES_C509_CERT - select when authentication can be based on CBOR encoded certificates, or
173   * EDHOC_BUF_SIZES_X509_CERT - select when authentication can be based on X.509 certificates
174   * EDHOC_MESSAGE_4_SUPPORTED - select when generation of message 4 should be supported
175
176*  **oscore.h**
177
178   * OSCORE_MAX_PLAINTEXT_LEN - expected maximal length of OSCORE packet
179   * E_OPTIONS_BUFF_MAX_LEN - expected maximal length of buffer with all encrypted CoAP options
180   * I_OPTIONS_BUFF_MAX_LEN - expected maximal length of buffer with all not encrypted CoAP options
181