1/* 2 * DTLS cookie callbacks implementation 3 * 4 * Copyright The Mbed TLS Contributors 5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6 */ 7/* 8 * These session callbacks use a simple chained list 9 * to store and retrieve the session information. 10 */ 11 12#include "common.h" 13 14#if defined(MBEDTLS_SSL_COOKIE_C) 15 16#include "mbedtls/platform.h" 17 18#include "mbedtls/ssl_cookie.h" 19#include "ssl_misc.h" 20#include "mbedtls/error.h" 21#include "mbedtls/platform_util.h" 22#include "mbedtls/constant_time.h" 23 24#include <string.h> 25 26#if defined(MBEDTLS_USE_PSA_CRYPTO) 27#include "mbedtls/psa_util.h" 28/* Define a local translating function to save code size by not using too many 29 * arguments in each translating place. */ 30static int local_err_translation(psa_status_t status) 31{ 32 return psa_status_to_mbedtls(status, psa_to_ssl_errors, 33 ARRAY_LENGTH(psa_to_ssl_errors), 34 psa_generic_status_to_mbedtls); 35} 36#define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status) 37#endif 38 39/* 40 * If DTLS is in use, then at least one of SHA-256 or SHA-384 is 41 * available. Try SHA-256 first as 384 wastes resources 42 */ 43#if defined(MBEDTLS_MD_CAN_SHA256) 44#define COOKIE_MD MBEDTLS_MD_SHA256 45#define COOKIE_MD_OUTLEN 32 46#define COOKIE_HMAC_LEN 28 47#elif defined(MBEDTLS_MD_CAN_SHA384) 48#define COOKIE_MD MBEDTLS_MD_SHA384 49#define COOKIE_MD_OUTLEN 48 50#define COOKIE_HMAC_LEN 28 51#else 52#error "DTLS hello verify needs SHA-256 or SHA-384" 53#endif 54 55/* 56 * Cookies are formed of a 4-bytes timestamp (or serial number) and 57 * an HMAC of timestamp and client ID. 58 */ 59#define COOKIE_LEN (4 + COOKIE_HMAC_LEN) 60 61void mbedtls_ssl_cookie_init(mbedtls_ssl_cookie_ctx *ctx) 62{ 63#if defined(MBEDTLS_USE_PSA_CRYPTO) 64 ctx->psa_hmac_key = MBEDTLS_SVC_KEY_ID_INIT; 65#else 66 mbedtls_md_init(&ctx->hmac_ctx); 67#endif /* MBEDTLS_USE_PSA_CRYPTO */ 68#if !defined(MBEDTLS_HAVE_TIME) 69 ctx->serial = 0; 70#endif 71 ctx->timeout = MBEDTLS_SSL_COOKIE_TIMEOUT; 72 73#if !defined(MBEDTLS_USE_PSA_CRYPTO) 74#if defined(MBEDTLS_THREADING_C) 75 mbedtls_mutex_init(&ctx->mutex); 76#endif 77#endif /* !MBEDTLS_USE_PSA_CRYPTO */ 78} 79 80void mbedtls_ssl_cookie_set_timeout(mbedtls_ssl_cookie_ctx *ctx, unsigned long delay) 81{ 82 ctx->timeout = delay; 83} 84 85void mbedtls_ssl_cookie_free(mbedtls_ssl_cookie_ctx *ctx) 86{ 87#if defined(MBEDTLS_USE_PSA_CRYPTO) 88 psa_destroy_key(ctx->psa_hmac_key); 89#else 90 mbedtls_md_free(&ctx->hmac_ctx); 91 92#if defined(MBEDTLS_THREADING_C) 93 mbedtls_mutex_free(&ctx->mutex); 94#endif 95#endif /* MBEDTLS_USE_PSA_CRYPTO */ 96 97 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ssl_cookie_ctx)); 98} 99 100int mbedtls_ssl_cookie_setup(mbedtls_ssl_cookie_ctx *ctx, 101 int (*f_rng)(void *, unsigned char *, size_t), 102 void *p_rng) 103{ 104#if defined(MBEDTLS_USE_PSA_CRYPTO) 105 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 106 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 107 psa_algorithm_t alg; 108 109 (void) f_rng; 110 (void) p_rng; 111 112 alg = mbedtls_md_psa_alg_from_type(COOKIE_MD); 113 if (alg == 0) { 114 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 115 } 116 117 ctx->psa_hmac_alg = PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(alg), 118 COOKIE_HMAC_LEN); 119 120 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_MESSAGE | 121 PSA_KEY_USAGE_SIGN_MESSAGE); 122 psa_set_key_algorithm(&attributes, ctx->psa_hmac_alg); 123 psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC); 124 psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(COOKIE_MD_OUTLEN)); 125 126 if ((status = psa_generate_key(&attributes, 127 &ctx->psa_hmac_key)) != PSA_SUCCESS) { 128 return PSA_TO_MBEDTLS_ERR(status); 129 } 130#else 131 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 132 unsigned char key[COOKIE_MD_OUTLEN]; 133 134 if ((ret = f_rng(p_rng, key, sizeof(key))) != 0) { 135 return ret; 136 } 137 138 ret = mbedtls_md_setup(&ctx->hmac_ctx, mbedtls_md_info_from_type(COOKIE_MD), 1); 139 if (ret != 0) { 140 return ret; 141 } 142 143 ret = mbedtls_md_hmac_starts(&ctx->hmac_ctx, key, sizeof(key)); 144 if (ret != 0) { 145 return ret; 146 } 147 148 mbedtls_platform_zeroize(key, sizeof(key)); 149#endif /* MBEDTLS_USE_PSA_CRYPTO */ 150 151 return 0; 152} 153 154#if !defined(MBEDTLS_USE_PSA_CRYPTO) 155/* 156 * Generate the HMAC part of a cookie 157 */ 158MBEDTLS_CHECK_RETURN_CRITICAL 159static int ssl_cookie_hmac(mbedtls_md_context_t *hmac_ctx, 160 const unsigned char time[4], 161 unsigned char **p, unsigned char *end, 162 const unsigned char *cli_id, size_t cli_id_len) 163{ 164 unsigned char hmac_out[COOKIE_MD_OUTLEN]; 165 166 MBEDTLS_SSL_CHK_BUF_PTR(*p, end, COOKIE_HMAC_LEN); 167 168 if (mbedtls_md_hmac_reset(hmac_ctx) != 0 || 169 mbedtls_md_hmac_update(hmac_ctx, time, 4) != 0 || 170 mbedtls_md_hmac_update(hmac_ctx, cli_id, cli_id_len) != 0 || 171 mbedtls_md_hmac_finish(hmac_ctx, hmac_out) != 0) { 172 return MBEDTLS_ERR_SSL_INTERNAL_ERROR; 173 } 174 175 memcpy(*p, hmac_out, COOKIE_HMAC_LEN); 176 *p += COOKIE_HMAC_LEN; 177 178 return 0; 179} 180#endif /* !MBEDTLS_USE_PSA_CRYPTO */ 181 182/* 183 * Generate cookie for DTLS ClientHello verification 184 */ 185int mbedtls_ssl_cookie_write(void *p_ctx, 186 unsigned char **p, unsigned char *end, 187 const unsigned char *cli_id, size_t cli_id_len) 188{ 189#if defined(MBEDTLS_USE_PSA_CRYPTO) 190 psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; 191 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 192 size_t sign_mac_length = 0; 193#endif 194 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 195 mbedtls_ssl_cookie_ctx *ctx = (mbedtls_ssl_cookie_ctx *) p_ctx; 196 unsigned long t; 197 198 if (ctx == NULL || cli_id == NULL) { 199 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 200 } 201 202 MBEDTLS_SSL_CHK_BUF_PTR(*p, end, COOKIE_LEN); 203 204#if defined(MBEDTLS_HAVE_TIME) 205 t = (unsigned long) mbedtls_time(NULL); 206#else 207 t = ctx->serial++; 208#endif 209 210 MBEDTLS_PUT_UINT32_BE(t, *p, 0); 211 *p += 4; 212 213#if defined(MBEDTLS_USE_PSA_CRYPTO) 214 status = psa_mac_sign_setup(&operation, ctx->psa_hmac_key, 215 ctx->psa_hmac_alg); 216 if (status != PSA_SUCCESS) { 217 ret = PSA_TO_MBEDTLS_ERR(status); 218 goto exit; 219 } 220 221 status = psa_mac_update(&operation, *p - 4, 4); 222 if (status != PSA_SUCCESS) { 223 ret = PSA_TO_MBEDTLS_ERR(status); 224 goto exit; 225 } 226 227 status = psa_mac_update(&operation, cli_id, cli_id_len); 228 if (status != PSA_SUCCESS) { 229 ret = PSA_TO_MBEDTLS_ERR(status); 230 goto exit; 231 } 232 233 status = psa_mac_sign_finish(&operation, *p, COOKIE_MD_OUTLEN, 234 &sign_mac_length); 235 if (status != PSA_SUCCESS) { 236 ret = PSA_TO_MBEDTLS_ERR(status); 237 goto exit; 238 } 239 240 *p += COOKIE_HMAC_LEN; 241 242 ret = 0; 243#else 244#if defined(MBEDTLS_THREADING_C) 245 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { 246 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_SSL_INTERNAL_ERROR, ret); 247 } 248#endif 249 250 ret = ssl_cookie_hmac(&ctx->hmac_ctx, *p - 4, 251 p, end, cli_id, cli_id_len); 252 253#if defined(MBEDTLS_THREADING_C) 254 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { 255 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_SSL_INTERNAL_ERROR, 256 MBEDTLS_ERR_THREADING_MUTEX_ERROR); 257 } 258#endif 259#endif /* MBEDTLS_USE_PSA_CRYPTO */ 260 261#if defined(MBEDTLS_USE_PSA_CRYPTO) 262exit: 263 status = psa_mac_abort(&operation); 264 if (status != PSA_SUCCESS) { 265 ret = PSA_TO_MBEDTLS_ERR(status); 266 } 267#endif /* MBEDTLS_USE_PSA_CRYPTO */ 268 return ret; 269} 270 271/* 272 * Check a cookie 273 */ 274int mbedtls_ssl_cookie_check(void *p_ctx, 275 const unsigned char *cookie, size_t cookie_len, 276 const unsigned char *cli_id, size_t cli_id_len) 277{ 278#if defined(MBEDTLS_USE_PSA_CRYPTO) 279 psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; 280 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 281#else 282 unsigned char ref_hmac[COOKIE_HMAC_LEN]; 283 unsigned char *p = ref_hmac; 284#endif 285 int ret = 0; 286 mbedtls_ssl_cookie_ctx *ctx = (mbedtls_ssl_cookie_ctx *) p_ctx; 287 unsigned long cur_time, cookie_time; 288 289 if (ctx == NULL || cli_id == NULL) { 290 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; 291 } 292 293 if (cookie_len != COOKIE_LEN) { 294 return -1; 295 } 296 297#if defined(MBEDTLS_USE_PSA_CRYPTO) 298 status = psa_mac_verify_setup(&operation, ctx->psa_hmac_key, 299 ctx->psa_hmac_alg); 300 if (status != PSA_SUCCESS) { 301 ret = PSA_TO_MBEDTLS_ERR(status); 302 goto exit; 303 } 304 305 status = psa_mac_update(&operation, cookie, 4); 306 if (status != PSA_SUCCESS) { 307 ret = PSA_TO_MBEDTLS_ERR(status); 308 goto exit; 309 } 310 311 status = psa_mac_update(&operation, cli_id, 312 cli_id_len); 313 if (status != PSA_SUCCESS) { 314 ret = PSA_TO_MBEDTLS_ERR(status); 315 goto exit; 316 } 317 318 status = psa_mac_verify_finish(&operation, cookie + 4, 319 COOKIE_HMAC_LEN); 320 if (status != PSA_SUCCESS) { 321 ret = PSA_TO_MBEDTLS_ERR(status); 322 goto exit; 323 } 324 325 ret = 0; 326#else 327#if defined(MBEDTLS_THREADING_C) 328 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { 329 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_SSL_INTERNAL_ERROR, ret); 330 } 331#endif 332 333 if (ssl_cookie_hmac(&ctx->hmac_ctx, cookie, 334 &p, p + sizeof(ref_hmac), 335 cli_id, cli_id_len) != 0) { 336 ret = -1; 337 } 338 339#if defined(MBEDTLS_THREADING_C) 340 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { 341 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_SSL_INTERNAL_ERROR, 342 MBEDTLS_ERR_THREADING_MUTEX_ERROR); 343 } 344#endif 345 346 if (ret != 0) { 347 goto exit; 348 } 349 350 if (mbedtls_ct_memcmp(cookie + 4, ref_hmac, sizeof(ref_hmac)) != 0) { 351 ret = -1; 352 goto exit; 353 } 354#endif /* MBEDTLS_USE_PSA_CRYPTO */ 355 356#if defined(MBEDTLS_HAVE_TIME) 357 cur_time = (unsigned long) mbedtls_time(NULL); 358#else 359 cur_time = ctx->serial; 360#endif 361 362 cookie_time = (unsigned long) MBEDTLS_GET_UINT32_BE(cookie, 0); 363 364 if (ctx->timeout != 0 && cur_time - cookie_time > ctx->timeout) { 365 ret = -1; 366 goto exit; 367 } 368 369exit: 370#if defined(MBEDTLS_USE_PSA_CRYPTO) 371 status = psa_mac_abort(&operation); 372 if (status != PSA_SUCCESS) { 373 ret = PSA_TO_MBEDTLS_ERR(status); 374 } 375#else 376 mbedtls_platform_zeroize(ref_hmac, sizeof(ref_hmac)); 377#endif /* MBEDTLS_USE_PSA_CRYPTO */ 378 return ret; 379} 380#endif /* MBEDTLS_SSL_COOKIE_C */ 381