1 /*
2  *  Copyright 2018-2024 NXP
3  *
4  *  SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 /** @file wm_mbedtls_helper_api.h
9  *
10  *  @brief This header file provides abstraction layer for mbedTLS stack
11  */
12 
13 #ifndef WM_MBEDTLS_HELPER_H
14 #define WM_MBEDTLS_HELPER_H
15 
16 #include <mbedtls/ssl.h>
17 #include <mbedtls/pk.h>
18 #include <wm_mbedtls_debug.h>
19 
20 /* NOTE:
21  *
22  * ca_chain object will be interpreted differently
23  * in case of two endpoints viz. 'CLIENT' or 'SERVER'.
24  *
25  * For 'CLIENT', 'ca_chain' refers to 'Certifying Authority (CA)
26  * certificate chain' present with CLIENT, which will be used to verify
27  * SERVER i.e. for 'SERVER verification by CLIENT'
28  *
29  * For 'SERVER', 'ca_chain' refers to 'chain of client certificates'
30  * present with SERVER, which will be used to verify CLIENT.
31  * i.e. 'CLIENT verification by SERVER'
32  */
33 
34 typedef struct
35 {
36     mbedtls_x509_crt *ca_chain;
37     mbedtls_x509_crt *own_cert;
38     mbedtls_pk_context *own_key;
39 } wm_mbedtls_cert_t;
40 
41 /**
42  * Initialize MBEDTLS library pre-requisites as following:
43  *
44  * Initialize time subsystem including RTC.
45  * Set memory callback functions for alloc, free
46  * Set threading callback function for mutex free, lock, unlock
47  * Setup global entropy, CTR_DRBG context.
48  *
49  * @return 0		Success
50  * @return -1		Failed in setup for entropy, CTR_DRBG context.
51  */
52 int wm_mbedtls_lib_init();
53 
54 /**
55  * Get wm_mbedtls library initialization status
56  *
57  * return true if initialized, false if not.
58  */
59 bool is_wm_mbedtls_lib_init();
60 
61 /**
62  * Parse char buffer into MBEDTLS X.509 certificate container
63  *
64  * This function allocates memory for MBEDTLS X.509 certificate
65  * container and parses input char buffer with its length into
66  * MBEDTLS X.509 certificate container.
67  *
68  * After parsing is done, then char buffer can be freed if
69  * dynamically allocated.
70  *
71  * Note: For PEM cert buffers, cert_buf must be null terminated
72  * and its length must account for the last null character '\0'.
73  * For DER cert buffers there is no such requirement.
74  *
75  * @param[in] cert_buf		A char cert buffer.
76  * @param[in] cert_buf_len	Length of cert_buf
77  *
78  * @return MBEDTLS X.509 certificate container, NULL in case of parse failure.
79  */
80 mbedtls_x509_crt *wm_mbedtls_parse_cert(const unsigned char *cert_buf, size_t cert_buf_len);
81 
82 /**
83  * Free MBEDTLS X.509 certificate container
84  *
85  * This function will free memory for following things:
86  *
87  * Allocations done by MBEDTLS itself internally.
88  * X.509 certificate container allocated by WMSDK.
89  *
90  * @param[in] cert		Pointer to MBEDTLS X.509 certificate container
91  */
92 void wm_mbedtls_free_cert(mbedtls_x509_crt *cert);
93 
94 /**
95  * Parse char buffer into MBEDTLS public key container
96  *
97  * This function allocates memory for MBEDTLS public key container
98  * and parses input char buffer with its length into
99  * MBEDTLS public key container.
100  *
101  * After parsing is done, then char buffer can be freed if
102  * dynamically allocated.
103  *
104  * Note: For PEM key buffers, key_buf must be null terminated
105  * and its length must account for the last null character '\0'.
106  * For DER key buffers there is no such requirement.
107  *
108  * @param[in] key_buf		A char key buffer of X.509 key.
109  * @param[in] key_len		Length of key_buf
110  *
111  * @param[in] pwd			Password string used to encrypt
112  * X.509 key. If password string is not used then pass 'NULL' here.
113  *
114  * @param[in] pwd_len		Length of pwd
115  *
116  * @return MBEDTLS public key container, NULL in case of parse failure.
117  */
118 mbedtls_pk_context *wm_mbedtls_parse_key(const unsigned char *key_buf,
119                                          size_t key_len,
120                                          const unsigned char *pwd,
121                                          size_t pwd_len);
122 
123 /**
124  * Free MBEDTLS public key container
125  *
126  * This function will free memory for following things:
127  *
128  * Allocations done by MBEDTLS itself internally
129  * Public key container allocated by WMSDK
130  *
131  * @param[in] key		Pointer to MBEDTLS public key container
132  */
133 void wm_mbedtls_free_key(mbedtls_pk_context *key);
134 
135 #ifdef MBEDTLS_DEBUG_C
136 /**
137  * Set debug function callback and debug threshold in SSL configuration context
138  *
139  * Please note that, MBEDTLS_DEBUG_C must be defined to use this api.
140  *
141  * @param[in] conf		MBEDTLS SSL configuration context
142  * @param[in] threshold	Debug threshold (Possible values: 0, 1, 2, 3, 4)
143  * @param[in] f_dbg		Function pointer to set in SSL configuration
144  * context. If 'NULL', then global dbg function will be set.
145  */
146 void wm_mbedtls_set_debug_cb(mbedtls_ssl_config *conf,
147                              int threshold,
148                              void (*f_dbg)(void *, int, const char *, int, const char *));
149 #endif /* MBEDTLS_DEBUG_C */
150 
151 /**
152  * Create MBEDTLS SSL configuration context
153  *
154  * This function create SSL configuration context as per
155  * input certificate structure, endpoint and authentication
156  * mode.
157  *
158  * Memory allocated and default values are set in SSL configuration
159  * context with input endpoint.
160  *
161  * Certificate structure is parsed and different entities in it such as
162  * ca_chain, own_cert, own_key are set.
163  *
164  * CTR_DRBG context along with MBEDTLS DRBG function (to generate
165  * random data) are registered in SSL configuration context.
166  *
167  * @param[in] cert			Certificate structure of ca_chain,
168  * own_cert, own_key. This structure should be populated by user.
169  * Appropriate buffers should be parsed into cert/key using apis
170  * wm_mbedtls_parse_cert or wm_mbedtls_parse_key.
171  *
172  * @param[in] endpoint		Endpoint i.e. device is client or server.
173  * There are 2 possible values: MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_IS_SERVER
174  *
175  * @param[in] authmode		Authentication mode to be imposed on peer-side.
176  * There are 4 possible values:
177  * MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL,
178  * MBEDTLS_SSL_VERIFY_REQUIRED, MBEDTLS_SSL_VERIFY_UNSET
179  *
180  * @return		Pointer to MBEDTLS SSL configuration context
181  */
182 mbedtls_ssl_config *wm_mbedtls_ssl_config_new(wm_mbedtls_cert_t *cert, int endpoint, int authmode);
183 
184 /**
185  * Set the maximum content length for each of the two internal I/O buffers
186  * (in and/or out) for a given SSL configuration at run-time.
187  * All values between 1 and 16384 (inclusive) are allowed.
188  *
189  * @note This function should be called after \ref wm_mbedtls_ssl_config_new
190  * and before \ref wm_mbedtls_ssl_new.
191  *
192  * @note The RFC defines the default size of SSL / TLS messages.
193  * If you change the value here, other clients / servers may not be able to
194  * communicate with you anymore. Only change this value if you control
195  * both sides of the connection and have it reduced at both sides, or
196  * if you're using the Max Fragment Length (MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
197  * extension and you know all your peers are using it too! (Ref: mbedtls/ssl.h)
198  *
199  * @note Setting MBEDTLS_SSL_MAX_CONTENT_LEN provides a compile-time mechanism
200  * to set the same maximum content length for all SSL / TLS sessions in all
201  * (in+out) directions. Additionally, WMSDKA has a run-time mechanism
202  * (\ref wm_mbedtls_ssl_conf_buffsizes()) to set maximum content length for a
203  * particular ssl session in a particular direction (in and/or out).
204  * Applications can use a combination of both mechanism to communicate
205  * with other ends of connection successfully and still be able to reduce
206  * memory footprint. WMSDKA has set a smaller default value of
207  * MBEDTLS_SSL_MAX_CONTENT_LEN to cater to most common use-cases
208  * (Ref: config/default.h), while using \ref wm_mbedtls_ssl_conf_buffsizes()
209  * in cases where transfer sizes can be larger, e.g. over-the-air upgrade of
210  * large firmware upgrade files over SSL / TLS.
211  *
212  * @note If Max Fragment Length (MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) extension is
213  * enabled, effective buffer length is rounded down to one of 512, 1024, 2048,
214  * 4096 or 16384 internally to avoid failures. It also supports values < 512
215  * bytes, in which case effective buffer length is set to actual value,
216  * disabling exchange of Max Fragment Length extension during handshake. This
217  * allows for maximum flexiblity by allowing all values between 1 to 16384.
218  * Applications can override the default behavior by calling
219  * mbedtls_ssl_conf_max_frag_len(conf, MBEDTLS_SSL_MAX_FRAG_LEN_NONE)
220  * after calling wm_mbedtls_ssl_conf_buffsizes(conf, in_buf_len, out_buf_len)
221  * in which case effective buffer length will be set exactly to
222  * (in_buf_len, out_buf_len), disabling the exchange
223  * of Max Fragment Length extension during handshake.
224  *
225  * @param[in] conf             SSL configuration
226  * @param[in] in_buf_len       size in bytes of in (receive) buffer,
227  *                             0 for default (MBEDTLS_SSL_MAX_CONTENT_LEN)
228  * @param[in] out_buf_len      size in bytes of out (send) buffer,
229  *                             0 for default (MBEDTLS_SSL_MAX_CONTENT_LEN)
230  *
231  * @return             0 if successful, -1 if feature is not supported
232  *                     (MBEDTLS_SSL_BUFFER_SIZES is not defined) or
233  *                     MBEDTLS_ERR_SSL_BAD_INPUT_DATA
234  */
235 int wm_mbedtls_ssl_conf_buffsizes(mbedtls_ssl_config *conf, size_t in_buf_len, size_t out_buf_len);
236 
237 /**
238  * Free MBEDTLS SSL configuration context
239  *
240  * This function will free memory for following things:
241  *
242  * Allocations done by MBEDTLS itself internally
243  * SSL configuration context allocated by WMSDK
244  *
245  * @param[in] conf		MBEDTLS SSL configuration context
246  */
247 void wm_mbedtls_ssl_config_free(mbedtls_ssl_config *conf);
248 
249 /**
250  * Create MBEDTLS SSL context
251  *
252  * This function creates a MBEDTLS SSL context as per input
253  * parameter MBEDTLS SSL configuration context, TCP socket
254  * file descriptor and hostname to which SSL connection will
255  * be done.
256  *
257  * Memory allocated for SSL context and MBEDTLS setup is done with
258  * configuration context.
259  *
260  * Underlying BIO callbacks for write, read and read-with-timeout
261  * along with socket file descriptor are set.
262  *
263  * Memory allocated for SSL internal timer, and set timer callbacks
264  *
265  * @param[in] conf		MBEDTLS SSL configuration context. This context
266  * can set using api \ref wm_mbedtls_ssl_config_new
267  *
268  * @param[in] fd		socket descriptor.
269  * @param[in] hostname	string denoting destination server name
270  *
271  * @return		Pointer to MBEDTLS SSL context
272  *
273  */
274 mbedtls_ssl_context *wm_mbedtls_ssl_new(mbedtls_ssl_config *conf, int fd, const char *hostname);
275 
276 /**
277  * Free MBEDTLS SSL context
278  *
279  * This function will free memory for following things:
280  *
281  * Internal timer for SSL context allocated by WMSDK
282  * Allocations done by MBEDTLS itself internally
283  * SSL context allocated by WMSDK
284  *
285  * @param[in] ssl		Pointer to MBEDTLS SSL context
286  *
287  */
288 void wm_mbedtls_ssl_free(mbedtls_ssl_context *ssl);
289 
290 /**
291  * Read at most 'len' application data bytes
292  *
293  * @param[in] ssl      SSL context
294  * @param[in] buf      buffer that will hold the data
295  * @param[in] len      maximum number of bytes to read
296  *
297  * @return         the number of bytes read, or
298  *                 0 for EOF, or
299  *                 MBEDTLS_ERR_SSL_CLIENT_RECONNECT (see below), or
300  *                 another negative error code.
301  *
302  * @note           If this function returns something other than a positive
303  *                 value or
304  *                 MBEDTLS_ERR_SSL_CLIENT_RECONNECT, then the ssl context
305  *                 becomes unusable, and you should either free it or call
306  *                 \c mbedtls_ssl_session_reset() on it before re-using it for
307  *                 a new connection; the current connection must be closed.
308  *
309  * @note           When this function return MBEDTLS_ERR_SSL_CLIENT_RECONNECT
310  *                 (which can only happen server-side), it means that a client
311  *                 is initiating a new connection using the same source port.
312  *                 You can either treat that as a connection close and wait
313  *                 for the client to resend a ClientHello, or directly
314  *                 continue with \c mbedtls_ssl_handshake() with the same
315  *                 context (as it has beeen reset internally). Either way, you
316  *                 should make sure this is seen by the application as a new
317  *                 connection: application state, if any, should be reset, and
318  *                 most importantly the identity of the client must be checked
319  *                 again. WARNING: not validating the identity of the client
320  *                 again, or not transmitting the new identity to the
321  *                 application layer, would allow authentication bypass!
322  *                 (Ref: mbedtls/ssl.h)
323  */
324 int wm_mbedtls_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len);
325 
326 /**
327  * Try to write exactly 'len' application data bytes
328  *
329  * @param[in] ssl      SSL context
330  * @param[in] buf      buffer holding the data
331  * @param[in] len      how many bytes must be written
332  *
333  * @return         the number of bytes actually written,
334  *                 0 for EOF, or
335  *                 or another negative error code.
336  *
337  * @note           If this function returns something other than a positive
338  *                 value, the ssl context
339  *                 becomes unusable, and you should either free it or call
340  *                 \c mbedtls_ssl_session_reset() on it before re-using it for
341  *                 a new connection; the current connection must be closed.
342  *                 (Ref: mbedtls/ssl.h)
343  *
344  * \note           If the requested length is greater than the maximum
345  *                 fragment length (either the built-in limit or the one set
346  *                 or negotiated with the peer), then:
347  *                 - with TLS, this function uses a loop to send all of
348  *                 requested data.
349  *                 - with DTLS, MBEDTLS_ERR_SSL_BAD_INPUT_DATA is returned.
350  *                 \c mbedtls_ssl_get_max_frag_len() may be used to query the
351  *                 active maximum fragment length.
352  */
353 int wm_mbedtls_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len);
354 
355 /**
356  * Reset MBEDTLS SSL internal timer
357  *
358  * This function resets MBEDTLS SSL internal timer. This function call
359  * is to done before every new call of 'wm_mbedtls_ssl_read'. Reason behind this
360  * is that, in each 'wm_mbedtls_ssl_read' call, if timer is not running, then
361  * MBEDTLS starts the timer with internal read timeout value (which can
362  * be set using \ref wm_mbedtls_set_read_timeout).
363  *
364  * In 'wm_mbedtls_ssl_read', timer status check is done before invoking
365  * functions * network layer read function (timer needs to be running
366  * i.e. status should be 'not expired').
367  *
368  * After 'wm_mbedtls_ssl_read' call is finished (in success or failure),
369  * the timer is still running.
370  *
371  * If 'wm_mbedtls_ssl_read' is again called, then 2 things
372  * are possible, either the timer is expired or not (since the timer is
373  * not reset i.e. it is still running from the time when first call to
374  * 'wm_mbedtls_ssl_read' was done)
375  *
376  * If timer is not expired then its fine, 'wm_mbedtls_ssl_read' call will
377  * proceed further as expected. But in case timer has expired then
378  * 'wm_mbedtls_ssl_read' will return SSL timeout error.
379  *
380  * @param[in] ssl		Pointer to MBEDTLS SSL context
381  *
382  */
383 void wm_mbedtls_reset_read_timer(mbedtls_ssl_context *ssl);
384 
385 /**
386  * Set read_timeout for MBEDTLS SSL read
387  *
388  * This function will set read timeout value, which is used
389  * by MBEDTLS for setting internal timer. The status of this timer
390  * is checked by MBEDTLS before calling network layer read function.
391  *
392  * @param[in] ssl		Pointer to MBEDTLS SSL context
393  * @param[in] timeout	Desired timeout value to be set
394  */
395 void wm_mbedtls_set_read_timeout(mbedtls_ssl_context *ssl, uint32_t timeout);
396 
397 /**
398  * Start SSL connection
399  *
400  * This function performs SSL handshake on existing TCP connection
401  * along with verification of data returned by server as per user
402  * specified verification flags provided at \ref wm_mbedtls_ssl_new
403  *
404  * @param[in] ssl	Pointer to MBEDTLS SSL context
405  *
406  * @return 0		Success
407  * @return Non-zero	Failure
408  */
409 int wm_mbedtls_ssl_connect(mbedtls_ssl_context *ssl);
410 
411 #endif /* WM_MBEDTLS_HELPER_H */
412