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