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