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