1 /* 2 * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* Dispatch functions for ccm mode */ 11 12 #include <openssl/proverr.h> 13 #include "prov/ciphercommon.h" 14 #include "prov/ciphercommon_ccm.h" 15 #include "prov/providercommon.h" 16 #include "fips/fipsindicator.h" 17 18 static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out, 19 size_t *padlen, const unsigned char *in, 20 size_t len); 21 22 static int ccm_tls_init(PROV_CCM_CTX *ctx, unsigned char *aad, size_t alen) 23 { 24 size_t len; 25 26 if (!ossl_prov_is_running() || alen != EVP_AEAD_TLS1_AAD_LEN) 27 return 0; 28 29 /* Save the aad for later use. */ 30 memcpy(ctx->buf, aad, alen); 31 ctx->tls_aad_len = alen; 32 33 len = ctx->buf[alen - 2] << 8 | ctx->buf[alen - 1]; 34 if (len < EVP_CCM_TLS_EXPLICIT_IV_LEN) 35 return 0; 36 37 /* Correct length for explicit iv. */ 38 len -= EVP_CCM_TLS_EXPLICIT_IV_LEN; 39 40 if (!ctx->enc) { 41 if (len < ctx->m) 42 return 0; 43 /* Correct length for tag. */ 44 len -= ctx->m; 45 } 46 ctx->buf[alen - 2] = (unsigned char)(len >> 8); 47 ctx->buf[alen - 1] = (unsigned char)(len & 0xff); 48 49 /* Extra padding: tag appended to record. */ 50 return ctx->m; 51 } 52 53 static int ccm_tls_iv_set_fixed(PROV_CCM_CTX *ctx, unsigned char *fixed, 54 size_t flen) 55 { 56 if (flen != EVP_CCM_TLS_FIXED_IV_LEN) 57 return 0; 58 59 /* Copy to first part of the iv. */ 60 memcpy(ctx->iv, fixed, flen); 61 return 1; 62 } 63 64 static size_t ccm_get_ivlen(PROV_CCM_CTX *ctx) 65 { 66 return 15 - ctx->l; 67 } 68 69 int ossl_ccm_set_ctx_params(void *vctx, const OSSL_PARAM params[]) 70 { 71 PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; 72 const OSSL_PARAM *p; 73 size_t sz; 74 75 if (ossl_param_is_empty(params)) 76 return 1; 77 78 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); 79 if (p != NULL) { 80 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 81 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 82 return 0; 83 } 84 if ((p->data_size & 1) || (p->data_size < 4) || p->data_size > 16) { 85 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH); 86 return 0; 87 } 88 89 if (p->data != NULL) { 90 if (ctx->enc) { 91 ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED); 92 return 0; 93 } 94 memcpy(ctx->buf, p->data, p->data_size); 95 ctx->tag_set = 1; 96 } 97 ctx->m = p->data_size; 98 } 99 100 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN); 101 if (p != NULL) { 102 size_t ivlen; 103 104 if (!OSSL_PARAM_get_size_t(p, &sz)) { 105 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 106 return 0; 107 } 108 ivlen = 15 - sz; 109 if (ivlen < 2 || ivlen > 8) { 110 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 111 return 0; 112 } 113 if (ctx->l != ivlen) { 114 ctx->l = ivlen; 115 ctx->iv_set = 0; 116 } 117 } 118 119 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); 120 if (p != NULL) { 121 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 122 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 123 return 0; 124 } 125 sz = ccm_tls_init(ctx, p->data, p->data_size); 126 if (sz == 0) { 127 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA); 128 return 0; 129 } 130 ctx->tls_aad_pad_sz = sz; 131 } 132 133 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED); 134 if (p != NULL) { 135 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 136 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 137 return 0; 138 } 139 if (ccm_tls_iv_set_fixed(ctx, p->data, p->data_size) == 0) { 140 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 141 return 0; 142 } 143 } 144 145 return 1; 146 } 147 148 int ossl_ccm_get_ctx_params(void *vctx, OSSL_PARAM params[]) 149 { 150 PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; 151 OSSL_PARAM *p; 152 153 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); 154 if (p != NULL && !OSSL_PARAM_set_size_t(p, ccm_get_ivlen(ctx))) { 155 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 156 return 0; 157 } 158 159 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); 160 if (p != NULL) { 161 size_t m = ctx->m; 162 163 if (!OSSL_PARAM_set_size_t(p, m)) { 164 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 165 return 0; 166 } 167 } 168 169 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); 170 if (p != NULL) { 171 if (ccm_get_ivlen(ctx) > p->data_size) { 172 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 173 return 0; 174 } 175 if (!OSSL_PARAM_set_octet_string(p, ctx->iv, p->data_size) 176 && !OSSL_PARAM_set_octet_ptr(p, &ctx->iv, p->data_size)) { 177 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 178 return 0; 179 } 180 } 181 182 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); 183 if (p != NULL) { 184 if (ccm_get_ivlen(ctx) > p->data_size) { 185 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 186 return 0; 187 } 188 if (!OSSL_PARAM_set_octet_string(p, ctx->iv, p->data_size) 189 && !OSSL_PARAM_set_octet_ptr(p, &ctx->iv, p->data_size)) { 190 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 191 return 0; 192 } 193 } 194 195 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); 196 if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) { 197 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 198 return 0; 199 } 200 201 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD); 202 if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) { 203 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 204 return 0; 205 } 206 207 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG); 208 if (p != NULL) { 209 if (!ctx->enc || !ctx->tag_set) { 210 ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_SET); 211 return 0; 212 } 213 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 214 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 215 return 0; 216 } 217 if (!ctx->hw->gettag(ctx, p->data, p->data_size)) 218 return 0; 219 ctx->tag_set = 0; 220 ctx->iv_set = 0; 221 ctx->len_set = 0; 222 } 223 return OSSL_FIPS_IND_GET_CTX_PARAM_APPROVED(ctx, params); 224 } 225 226 static int ccm_init(void *vctx, const unsigned char *key, size_t keylen, 227 const unsigned char *iv, size_t ivlen, 228 const OSSL_PARAM params[], int enc) 229 { 230 PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; 231 232 if (!ossl_prov_is_running()) 233 return 0; 234 235 ctx->enc = enc; 236 237 if (iv != NULL) { 238 if (ivlen != ccm_get_ivlen(ctx)) { 239 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 240 return 0; 241 } 242 memcpy(ctx->iv, iv, ivlen); 243 ctx->iv_set = 1; 244 } 245 if (key != NULL) { 246 if (keylen != ctx->keylen) { 247 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 248 return 0; 249 } 250 if (!ctx->hw->setkey(ctx, key, keylen)) 251 return 0; 252 } 253 return ossl_ccm_set_ctx_params(ctx, params); 254 } 255 256 int ossl_ccm_einit(void *vctx, const unsigned char *key, size_t keylen, 257 const unsigned char *iv, size_t ivlen, 258 const OSSL_PARAM params[]) 259 { 260 return ccm_init(vctx, key, keylen, iv, ivlen, params, 1); 261 } 262 263 int ossl_ccm_dinit(void *vctx, const unsigned char *key, size_t keylen, 264 const unsigned char *iv, size_t ivlen, 265 const OSSL_PARAM params[]) 266 { 267 return ccm_init(vctx, key, keylen, iv, ivlen, params, 0); 268 } 269 270 int ossl_ccm_stream_update(void *vctx, unsigned char *out, size_t *outl, 271 size_t outsize, const unsigned char *in, 272 size_t inl) 273 { 274 PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; 275 276 if (outsize < inl) { 277 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 278 return 0; 279 } 280 281 if (!ccm_cipher_internal(ctx, out, outl, in, inl)) { 282 ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); 283 return 0; 284 } 285 return 1; 286 } 287 288 int ossl_ccm_stream_final(void *vctx, unsigned char *out, size_t *outl, 289 size_t outsize) 290 { 291 PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; 292 unsigned char dummy_in = 0, dummy_out = 0; 293 294 if (!ossl_prov_is_running()) 295 return 0; 296 297 /* 298 * Encryption sets tag_set after processing the payload, while successful 299 * decryption clears iv_set. Use those transitions to avoid processing an 300 * operation twice. 301 */ 302 if (!ctx->key_set 303 || (ctx->iv_set && (!ctx->enc || !ctx->tag_set) 304 && ccm_cipher_internal(ctx, &dummy_out, outl, &dummy_in, 0) <= 0)) 305 return 0; 306 307 *outl = 0; 308 return 1; 309 } 310 311 int ossl_ccm_cipher(void *vctx, unsigned char *out, size_t *outl, size_t outsize, 312 const unsigned char *in, size_t inl) 313 { 314 PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; 315 316 if (!ossl_prov_is_running()) 317 return 0; 318 319 if (in == NULL) 320 return ossl_ccm_stream_final(vctx, out, outl, outsize); 321 322 if (outsize < inl) { 323 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 324 return 0; 325 } 326 327 if (ccm_cipher_internal(ctx, out, outl, in, inl) <= 0) 328 return 0; 329 330 *outl = inl; 331 return 1; 332 } 333 334 /* Copy the buffered iv */ 335 static int ccm_set_iv(PROV_CCM_CTX *ctx, size_t mlen) 336 { 337 const PROV_CCM_HW *hw = ctx->hw; 338 339 if (!hw->setiv(ctx, ctx->iv, ccm_get_ivlen(ctx), mlen)) 340 return 0; 341 ctx->len_set = 1; 342 return 1; 343 } 344 345 static int ccm_tls_cipher(PROV_CCM_CTX *ctx, 346 unsigned char *out, size_t *padlen, 347 const unsigned char *in, size_t len) 348 { 349 int rv = 0; 350 size_t olen = 0; 351 352 if (!ossl_prov_is_running()) 353 goto err; 354 355 /* Encrypt/decrypt must be performed in place */ 356 if (in == NULL || out != in || len < EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m) 357 goto err; 358 359 /* If encrypting set explicit IV from sequence number (start of AAD) */ 360 if (ctx->enc) 361 memcpy(out, ctx->buf, EVP_CCM_TLS_EXPLICIT_IV_LEN); 362 /* Get rest of IV from explicit IV */ 363 memcpy(ctx->iv + EVP_CCM_TLS_FIXED_IV_LEN, in, EVP_CCM_TLS_EXPLICIT_IV_LEN); 364 /* Correct length value */ 365 len -= EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m; 366 if (!ccm_set_iv(ctx, len)) 367 goto err; 368 369 /* Use saved AAD */ 370 if (!ctx->hw->setaad(ctx, ctx->buf, ctx->tls_aad_len)) 371 goto err; 372 373 /* Fix buffer to point to payload */ 374 in += EVP_CCM_TLS_EXPLICIT_IV_LEN; 375 out += EVP_CCM_TLS_EXPLICIT_IV_LEN; 376 if (ctx->enc) { 377 if (!ctx->hw->auth_encrypt(ctx, in, out, len, out + len, ctx->m)) 378 goto err; 379 olen = len + EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m; 380 } else { 381 if (!ctx->hw->auth_decrypt(ctx, in, out, len, 382 (unsigned char *)in + len, ctx->m)) 383 goto err; 384 olen = len; 385 } 386 rv = 1; 387 err: 388 *padlen = olen; 389 return rv; 390 } 391 392 static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out, 393 size_t *padlen, const unsigned char *in, 394 size_t len) 395 { 396 int rv = 0; 397 size_t olen = 0; 398 const PROV_CCM_HW *hw = ctx->hw; 399 400 /* If no key set, return error */ 401 if (!ctx->key_set) 402 return 0; 403 404 if (ctx->tls_aad_len != UNINITIALISED_SIZET) 405 return ccm_tls_cipher(ctx, out, padlen, in, len); 406 407 /* EVP_*Final() doesn't return any data */ 408 if (in == NULL && out != NULL) 409 goto finish; 410 411 if (!ctx->iv_set) 412 goto err; 413 414 if (out == NULL) { 415 if (in == NULL) { 416 if (!ccm_set_iv(ctx, len)) 417 goto err; 418 } else { 419 /* If we have AAD, we need a message length */ 420 if (!ctx->len_set && len) 421 goto err; 422 if (!hw->setaad(ctx, in, len)) 423 goto err; 424 } 425 } else { 426 /* If not set length yet do it */ 427 if (!ctx->len_set && !ccm_set_iv(ctx, len)) 428 goto err; 429 430 if (ctx->enc) { 431 if (!hw->auth_encrypt(ctx, in, out, len, NULL, 0)) 432 goto err; 433 ctx->tag_set = 1; 434 } else { 435 /* The tag must be set before actually decrypting data */ 436 if (!ctx->tag_set) 437 goto err; 438 439 if (!hw->auth_decrypt(ctx, in, out, len, ctx->buf, ctx->m)) 440 goto err; 441 /* Finished - reset flags so calling this method again will fail */ 442 ctx->iv_set = 0; 443 ctx->tag_set = 0; 444 ctx->len_set = 0; 445 } 446 } 447 olen = len; 448 finish: 449 rv = 1; 450 err: 451 *padlen = olen; 452 return rv; 453 } 454 455 void ossl_ccm_initctx(PROV_CCM_CTX *ctx, size_t keybits, const PROV_CCM_HW *hw) 456 { 457 ctx->keylen = keybits / 8; 458 ctx->key_set = 0; 459 ctx->iv_set = 0; 460 ctx->tag_set = 0; 461 ctx->len_set = 0; 462 ctx->l = 8; 463 ctx->m = 12; 464 ctx->tls_aad_len = UNINITIALISED_SIZET; 465 ctx->hw = hw; 466 } 467