1 /* 2 * Copyright 2018-2024 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 /* 11 * CMAC low level APIs are deprecated for public use, but still ok for internal 12 * use. 13 */ 14 #include "internal/deprecated.h" 15 16 #include <openssl/core_dispatch.h> 17 #include <openssl/core_names.h> 18 #include <openssl/params.h> 19 #include <openssl/evp.h> 20 #include <openssl/cmac.h> 21 #include <openssl/err.h> 22 #include <openssl/proverr.h> 23 24 #include "prov/securitycheck.h" 25 #include "prov/implementations.h" 26 #include "prov/provider_ctx.h" 27 #include "prov/provider_util.h" 28 #include "prov/providercommon.h" 29 #include "crypto/cmac.h" 30 31 /* 32 * Forward declaration of everything implemented here. This is not strictly 33 * necessary for the compiler, but provides an assurance that the signatures 34 * of the functions in the dispatch table are correct. 35 */ 36 static OSSL_FUNC_mac_newctx_fn cmac_new; 37 static OSSL_FUNC_mac_dupctx_fn cmac_dup; 38 static OSSL_FUNC_mac_freectx_fn cmac_free; 39 static OSSL_FUNC_mac_gettable_ctx_params_fn cmac_gettable_ctx_params; 40 static OSSL_FUNC_mac_get_ctx_params_fn cmac_get_ctx_params; 41 static OSSL_FUNC_mac_settable_ctx_params_fn cmac_settable_ctx_params; 42 static OSSL_FUNC_mac_set_ctx_params_fn cmac_set_ctx_params; 43 static OSSL_FUNC_mac_init_fn cmac_init; 44 static OSSL_FUNC_mac_update_fn cmac_update; 45 static OSSL_FUNC_mac_final_fn cmac_final; 46 47 /* local CMAC data */ 48 49 struct cmac_data_st { 50 void *provctx; 51 CMAC_CTX *ctx; 52 PROV_CIPHER cipher; 53 OSSL_FIPS_IND_DECLARE 54 }; 55 56 static void *cmac_new(void *provctx) 57 { 58 struct cmac_data_st *macctx; 59 60 if (!ossl_prov_is_running()) 61 return NULL; 62 63 if ((macctx = OPENSSL_zalloc(sizeof(*macctx))) == NULL 64 || (macctx->ctx = CMAC_CTX_new()) == NULL) { 65 OPENSSL_free(macctx); 66 macctx = NULL; 67 } else { 68 macctx->provctx = provctx; 69 OSSL_FIPS_IND_INIT(macctx) 70 } 71 72 return macctx; 73 } 74 75 static void cmac_free(void *vmacctx) 76 { 77 struct cmac_data_st *macctx = vmacctx; 78 79 if (macctx != NULL) { 80 CMAC_CTX_free(macctx->ctx); 81 ossl_prov_cipher_reset(&macctx->cipher); 82 OPENSSL_free(macctx); 83 } 84 } 85 86 static void *cmac_dup(void *vsrc) 87 { 88 struct cmac_data_st *src = vsrc; 89 struct cmac_data_st *dst; 90 91 if (!ossl_prov_is_running()) 92 return NULL; 93 94 dst = cmac_new(src->provctx); 95 if (dst == NULL) 96 return NULL; 97 if (!CMAC_CTX_copy(dst->ctx, src->ctx) 98 || !ossl_prov_cipher_copy(&dst->cipher, &src->cipher)) { 99 cmac_free(dst); 100 return NULL; 101 } 102 OSSL_FIPS_IND_COPY(dst, src) 103 return dst; 104 } 105 106 static size_t cmac_size(void *vmacctx) 107 { 108 struct cmac_data_st *macctx = vmacctx; 109 const EVP_CIPHER_CTX *cipherctx = CMAC_CTX_get0_cipher_ctx(macctx->ctx); 110 111 if (EVP_CIPHER_CTX_get0_cipher(cipherctx) == NULL) 112 return 0; 113 114 return EVP_CIPHER_CTX_get_block_size(cipherctx); 115 } 116 117 #ifdef FIPS_MODULE 118 /* 119 * TDES Encryption is not approved in FIPS 140-3. 120 * 121 * In strict approved mode we just fail here (by returning 0). 122 * If we are going to bypass it using a FIPS indicator then we need to pass that 123 * information down to the cipher also. 124 * This function returns the param to pass down in 'p'. 125 * state will return OSSL_FIPS_IND_STATE_UNKNOWN if the param has not been set. 126 * 127 * The name 'OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK' used below matches the 128 * key name used by the Triple-DES. 129 */ 130 static int tdes_check_param(struct cmac_data_st *macctx, OSSL_PARAM *p, 131 int *state) 132 { 133 OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(macctx->provctx); 134 const EVP_CIPHER *cipher = ossl_prov_cipher_cipher(&macctx->cipher); 135 136 *state = OSSL_FIPS_IND_STATE_UNKNOWN; 137 if (EVP_CIPHER_is_a(cipher, "DES-EDE3-CBC")) { 138 if (!OSSL_FIPS_IND_ON_UNAPPROVED(macctx, OSSL_FIPS_IND_SETTABLE0, 139 libctx, "CMAC", "Triple-DES", 140 ossl_fips_config_tdes_encrypt_disallowed)) 141 return 0; 142 OSSL_FIPS_IND_GET_PARAM(macctx, p, state, OSSL_FIPS_IND_SETTABLE0, 143 OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK) 144 } 145 return 1; 146 } 147 #endif 148 149 static int cmac_setkey(struct cmac_data_st *macctx, 150 const unsigned char *key, size_t keylen) 151 { 152 int rv; 153 OSSL_PARAM *p = NULL; 154 #ifdef FIPS_MODULE 155 int state = OSSL_FIPS_IND_STATE_UNKNOWN; 156 OSSL_PARAM prms[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; 157 158 if (!tdes_check_param(macctx, &prms[0], &state)) 159 return 0; 160 if (state != OSSL_FIPS_IND_STATE_UNKNOWN) 161 p = prms; 162 #endif 163 rv = ossl_cmac_init(macctx->ctx, key, keylen, 164 ossl_prov_cipher_cipher(&macctx->cipher), 165 ossl_prov_cipher_engine(&macctx->cipher), p); 166 ossl_prov_cipher_reset(&macctx->cipher); 167 return rv; 168 } 169 170 static int cmac_init(void *vmacctx, const unsigned char *key, 171 size_t keylen, const OSSL_PARAM params[]) 172 { 173 struct cmac_data_st *macctx = vmacctx; 174 175 if (!ossl_prov_is_running() || !cmac_set_ctx_params(macctx, params)) 176 return 0; 177 if (key != NULL) 178 return cmac_setkey(macctx, key, keylen); 179 /* Reinitialize the CMAC context */ 180 return CMAC_Init(macctx->ctx, NULL, 0, NULL, NULL); 181 } 182 183 static int cmac_update(void *vmacctx, const unsigned char *data, 184 size_t datalen) 185 { 186 struct cmac_data_st *macctx = vmacctx; 187 188 return CMAC_Update(macctx->ctx, data, datalen); 189 } 190 191 static int cmac_final(void *vmacctx, unsigned char *out, size_t *outl, 192 size_t outsize) 193 { 194 struct cmac_data_st *macctx = vmacctx; 195 196 if (!ossl_prov_is_running()) 197 return 0; 198 199 return CMAC_Final(macctx->ctx, out, outl); 200 } 201 202 static const OSSL_PARAM known_gettable_ctx_params[] = { 203 OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), 204 OSSL_PARAM_size_t(OSSL_MAC_PARAM_BLOCK_SIZE, NULL), 205 OSSL_FIPS_IND_GETTABLE_CTX_PARAM() 206 OSSL_PARAM_END 207 }; 208 static const OSSL_PARAM *cmac_gettable_ctx_params(ossl_unused void *ctx, 209 ossl_unused void *provctx) 210 { 211 return known_gettable_ctx_params; 212 } 213 214 static int cmac_get_ctx_params(void *vmacctx, OSSL_PARAM params[]) 215 { 216 OSSL_PARAM *p; 217 218 if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE)) != NULL 219 && !OSSL_PARAM_set_size_t(p, cmac_size(vmacctx))) 220 return 0; 221 222 if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_BLOCK_SIZE)) != NULL 223 && !OSSL_PARAM_set_size_t(p, cmac_size(vmacctx))) 224 return 0; 225 226 if (!OSSL_FIPS_IND_GET_CTX_PARAM((struct cmac_data_st *)vmacctx, params)) 227 return 0; 228 return 1; 229 } 230 231 static const OSSL_PARAM known_settable_ctx_params[] = { 232 OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_CIPHER, NULL, 0), 233 OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_PROPERTIES, NULL, 0), 234 OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), 235 OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK) 236 OSSL_PARAM_END 237 }; 238 static const OSSL_PARAM *cmac_settable_ctx_params(ossl_unused void *ctx, 239 ossl_unused void *provctx) 240 { 241 return known_settable_ctx_params; 242 } 243 244 /* 245 * ALL parameters should be set before init(). 246 */ 247 static int cmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[]) 248 { 249 struct cmac_data_st *macctx = vmacctx; 250 OSSL_LIB_CTX *ctx = PROV_LIBCTX_OF(macctx->provctx); 251 const OSSL_PARAM *p; 252 253 if (ossl_param_is_empty(params)) 254 return 1; 255 256 if (!OSSL_FIPS_IND_SET_CTX_PARAM(macctx, 257 OSSL_FIPS_IND_SETTABLE0, params, 258 OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK)) 259 return 0; 260 261 if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_CIPHER)) != NULL) { 262 if (!ossl_prov_cipher_load_from_params(&macctx->cipher, params, ctx)) 263 return 0; 264 265 if (EVP_CIPHER_get_mode(ossl_prov_cipher_cipher(&macctx->cipher)) 266 != EVP_CIPH_CBC_MODE) { 267 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); 268 return 0; 269 } 270 #ifdef FIPS_MODULE 271 { 272 const EVP_CIPHER *cipher = ossl_prov_cipher_cipher(&macctx->cipher); 273 274 if (!EVP_CIPHER_is_a(cipher, "AES-256-CBC") 275 && !EVP_CIPHER_is_a(cipher, "AES-192-CBC") 276 && !EVP_CIPHER_is_a(cipher, "AES-128-CBC") 277 && !EVP_CIPHER_is_a(cipher, "DES-EDE3-CBC")) { 278 ERR_raise(ERR_LIB_PROV, EVP_R_UNSUPPORTED_CIPHER); 279 return 0; 280 } 281 } 282 #endif 283 } 284 285 if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL) { 286 if (p->data_type != OSSL_PARAM_OCTET_STRING) 287 return 0; 288 return cmac_setkey(macctx, p->data, p->data_size); 289 } 290 return 1; 291 } 292 293 const OSSL_DISPATCH ossl_cmac_functions[] = { 294 { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))cmac_new }, 295 { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))cmac_dup }, 296 { OSSL_FUNC_MAC_FREECTX, (void (*)(void))cmac_free }, 297 { OSSL_FUNC_MAC_INIT, (void (*)(void))cmac_init }, 298 { OSSL_FUNC_MAC_UPDATE, (void (*)(void))cmac_update }, 299 { OSSL_FUNC_MAC_FINAL, (void (*)(void))cmac_final }, 300 { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, 301 (void (*)(void))cmac_gettable_ctx_params }, 302 { OSSL_FUNC_MAC_GET_CTX_PARAMS, (void (*)(void))cmac_get_ctx_params }, 303 { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, 304 (void (*)(void))cmac_settable_ctx_params }, 305 { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))cmac_set_ctx_params }, 306 OSSL_DISPATCH_END 307 }; 308