1 /* 2 * Copyright 2019-2025 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 chacha20_poly1305 cipher */ 11 12 #include <openssl/proverr.h> 13 #include "cipher_chacha20_poly1305.h" 14 #include "prov/implementations.h" 15 #include "prov/providercommon.h" 16 17 #define CHACHA20_POLY1305_KEYLEN CHACHA_KEY_SIZE 18 #define CHACHA20_POLY1305_BLKLEN 1 19 #define CHACHA20_POLY1305_MAX_IVLEN 12 20 #define CHACHA20_POLY1305_MODE 0 21 #define CHACHA20_POLY1305_FLAGS (PROV_CIPHER_FLAG_AEAD \ 22 | PROV_CIPHER_FLAG_CUSTOM_IV) 23 24 static OSSL_FUNC_cipher_newctx_fn chacha20_poly1305_newctx; 25 static OSSL_FUNC_cipher_freectx_fn chacha20_poly1305_freectx; 26 static OSSL_FUNC_cipher_dupctx_fn chacha20_poly1305_dupctx; 27 static OSSL_FUNC_cipher_encrypt_init_fn chacha20_poly1305_einit; 28 static OSSL_FUNC_cipher_decrypt_init_fn chacha20_poly1305_dinit; 29 static OSSL_FUNC_cipher_get_params_fn chacha20_poly1305_get_params; 30 static OSSL_FUNC_cipher_get_ctx_params_fn chacha20_poly1305_get_ctx_params; 31 static OSSL_FUNC_cipher_set_ctx_params_fn chacha20_poly1305_set_ctx_params; 32 static OSSL_FUNC_cipher_cipher_fn chacha20_poly1305_cipher; 33 static OSSL_FUNC_cipher_final_fn chacha20_poly1305_final; 34 static OSSL_FUNC_cipher_gettable_ctx_params_fn chacha20_poly1305_gettable_ctx_params; 35 static OSSL_FUNC_cipher_settable_ctx_params_fn chacha20_poly1305_settable_ctx_params; 36 #define chacha20_poly1305_gettable_params ossl_cipher_generic_gettable_params 37 #define chacha20_poly1305_update chacha20_poly1305_cipher 38 39 static void *chacha20_poly1305_newctx(void *provctx) 40 { 41 PROV_CHACHA20_POLY1305_CTX *ctx; 42 43 if (!ossl_prov_is_running()) 44 return NULL; 45 46 ctx = OPENSSL_zalloc(sizeof(*ctx)); 47 if (ctx != NULL) { 48 ossl_cipher_generic_initkey(&ctx->base, CHACHA20_POLY1305_KEYLEN * 8, 49 CHACHA20_POLY1305_BLKLEN * 8, 50 CHACHA20_POLY1305_IVLEN * 8, 51 CHACHA20_POLY1305_MODE, 52 CHACHA20_POLY1305_FLAGS, 53 ossl_prov_cipher_hw_chacha20_poly1305( 54 CHACHA20_POLY1305_KEYLEN * 8), 55 NULL); 56 ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH; 57 ossl_chacha20_initctx(&ctx->chacha); 58 } 59 return ctx; 60 } 61 62 static void *chacha20_poly1305_dupctx(void *provctx) 63 { 64 PROV_CHACHA20_POLY1305_CTX *ctx = provctx; 65 PROV_CHACHA20_POLY1305_CTX *dctx = NULL; 66 67 if (ctx == NULL) 68 return NULL; 69 dctx = OPENSSL_memdup(ctx, sizeof(*ctx)); 70 if (dctx != NULL && dctx->base.tlsmac != NULL && dctx->base.alloced) { 71 dctx->base.tlsmac = OPENSSL_memdup(dctx->base.tlsmac, 72 dctx->base.tlsmacsize); 73 if (dctx->base.tlsmac == NULL) { 74 OPENSSL_free(dctx); 75 dctx = NULL; 76 } 77 } 78 return dctx; 79 } 80 81 static void chacha20_poly1305_freectx(void *vctx) 82 { 83 PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; 84 85 if (ctx != NULL) { 86 ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); 87 OPENSSL_clear_free(ctx, sizeof(*ctx)); 88 } 89 } 90 91 static int chacha20_poly1305_get_params(OSSL_PARAM params[]) 92 { 93 return ossl_cipher_generic_get_params(params, 0, CHACHA20_POLY1305_FLAGS, 94 CHACHA20_POLY1305_KEYLEN * 8, 95 CHACHA20_POLY1305_BLKLEN * 8, 96 CHACHA20_POLY1305_IVLEN * 8); 97 } 98 99 static int chacha20_poly1305_get_ctx_params(void *vctx, OSSL_PARAM params[]) 100 { 101 PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; 102 OSSL_PARAM *p; 103 104 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); 105 if (p != NULL) { 106 if (!OSSL_PARAM_set_size_t(p, CHACHA20_POLY1305_IVLEN)) { 107 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 108 return 0; 109 } 110 } 111 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); 112 if (p != NULL && !OSSL_PARAM_set_size_t(p, CHACHA20_POLY1305_KEYLEN)) { 113 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 114 return 0; 115 } 116 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); 117 if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tag_len)) { 118 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 119 return 0; 120 } 121 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD); 122 if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) { 123 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 124 return 0; 125 } 126 127 p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG); 128 if (p != NULL) { 129 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 130 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); 131 return 0; 132 } 133 if (!ctx->base.enc) { 134 ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_SET); 135 return 0; 136 } 137 if (p->data_size == 0 || p->data_size > POLY1305_BLOCK_SIZE) { 138 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH); 139 return 0; 140 } 141 memcpy(p->data, ctx->tag, p->data_size); 142 } 143 144 return 1; 145 } 146 147 static const OSSL_PARAM chacha20_poly1305_known_gettable_ctx_params[] = { 148 OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), 149 OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), 150 OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL), 151 OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), 152 OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL), 153 OSSL_PARAM_END 154 }; 155 static const OSSL_PARAM *chacha20_poly1305_gettable_ctx_params 156 (ossl_unused void *cctx, ossl_unused void *provctx) 157 { 158 return chacha20_poly1305_known_gettable_ctx_params; 159 } 160 161 static const OSSL_PARAM chacha20_poly1305_known_settable_ctx_params[] = { 162 OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), 163 OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), 164 OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), 165 OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD, NULL, 0), 166 OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED, NULL, 0), 167 OSSL_PARAM_END 168 }; 169 static const OSSL_PARAM *chacha20_poly1305_settable_ctx_params( 170 ossl_unused void *cctx, ossl_unused void *provctx 171 ) 172 { 173 return chacha20_poly1305_known_settable_ctx_params; 174 } 175 176 static int chacha20_poly1305_set_ctx_params(void *vctx, 177 const OSSL_PARAM params[]) 178 { 179 const OSSL_PARAM *p; 180 size_t len; 181 PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; 182 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 183 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->base.hw; 184 185 if (ossl_param_is_empty(params)) 186 return 1; 187 188 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); 189 if (p != NULL) { 190 if (!OSSL_PARAM_get_size_t(p, &len)) { 191 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 192 return 0; 193 } 194 if (len != CHACHA20_POLY1305_KEYLEN) { 195 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 196 return 0; 197 } 198 } 199 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); 200 if (p != NULL) { 201 if (!OSSL_PARAM_get_size_t(p, &len)) { 202 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 203 return 0; 204 } 205 if (len != CHACHA20_POLY1305_MAX_IVLEN) { 206 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 207 return 0; 208 } 209 } 210 211 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); 212 if (p != NULL) { 213 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 214 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 215 return 0; 216 } 217 if (p->data_size == 0 || p->data_size > POLY1305_BLOCK_SIZE) { 218 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH); 219 return 0; 220 } 221 if (p->data != NULL) { 222 if (ctx->base.enc) { 223 ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED); 224 return 0; 225 } 226 memcpy(ctx->tag, p->data, p->data_size); 227 } 228 ctx->tag_len = p->data_size; 229 } 230 231 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); 232 if (p != NULL) { 233 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 234 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 235 return 0; 236 } 237 len = hw->tls_init(&ctx->base, p->data, p->data_size); 238 if (len == 0) { 239 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA); 240 return 0; 241 } 242 ctx->tls_aad_pad_sz = len; 243 } 244 245 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED); 246 if (p != NULL) { 247 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 248 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 249 return 0; 250 } 251 if (hw->tls_iv_set_fixed(&ctx->base, p->data, p->data_size) == 0) { 252 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 253 return 0; 254 } 255 } 256 return 1; 257 } 258 259 static int chacha20_poly1305_einit(void *vctx, const unsigned char *key, 260 size_t keylen, const unsigned char *iv, 261 size_t ivlen, const OSSL_PARAM params[]) 262 { 263 int ret; 264 265 /* The generic function checks for ossl_prov_is_running() */ 266 ret = ossl_cipher_generic_einit(vctx, key, keylen, iv, ivlen, NULL); 267 if (ret && iv != NULL) { 268 PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; 269 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 270 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; 271 272 hw->initiv(ctx); 273 } 274 if (ret && !chacha20_poly1305_set_ctx_params(vctx, params)) 275 ret = 0; 276 return ret; 277 } 278 279 static int chacha20_poly1305_dinit(void *vctx, const unsigned char *key, 280 size_t keylen, const unsigned char *iv, 281 size_t ivlen, const OSSL_PARAM params[]) 282 { 283 int ret; 284 285 /* The generic function checks for ossl_prov_is_running() */ 286 ret = ossl_cipher_generic_dinit(vctx, key, keylen, iv, ivlen, NULL); 287 if (ret && iv != NULL) { 288 PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; 289 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 290 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; 291 292 hw->initiv(ctx); 293 } 294 if (ret && !chacha20_poly1305_set_ctx_params(vctx, params)) 295 ret = 0; 296 return ret; 297 } 298 299 static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, 300 size_t *outl, size_t outsize, 301 const unsigned char *in, size_t inl) 302 { 303 PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; 304 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 305 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; 306 307 if (!ossl_prov_is_running()) 308 return 0; 309 310 if (inl == 0) { 311 *outl = 0; 312 return 1; 313 } 314 315 if (outsize < inl) { 316 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 317 return 0; 318 } 319 320 if (!hw->aead_cipher(ctx, out, outl, in, inl)) 321 return 0; 322 323 return 1; 324 } 325 326 static int chacha20_poly1305_final(void *vctx, unsigned char *out, size_t *outl, 327 size_t outsize) 328 { 329 PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; 330 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 331 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; 332 333 if (!ossl_prov_is_running()) 334 return 0; 335 336 if (hw->aead_cipher(ctx, out, outl, NULL, 0) <= 0) 337 return 0; 338 339 *outl = 0; 340 return 1; 341 } 342 343 /* ossl_chacha20_ossl_poly1305_functions */ 344 const OSSL_DISPATCH ossl_chacha20_ossl_poly1305_functions[] = { 345 { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))chacha20_poly1305_newctx }, 346 { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))chacha20_poly1305_freectx }, 347 { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))chacha20_poly1305_dupctx }, 348 { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))chacha20_poly1305_einit }, 349 { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))chacha20_poly1305_dinit }, 350 { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))chacha20_poly1305_update }, 351 { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))chacha20_poly1305_final }, 352 { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))chacha20_poly1305_cipher }, 353 { OSSL_FUNC_CIPHER_GET_PARAMS, 354 (void (*)(void))chacha20_poly1305_get_params }, 355 { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, 356 (void (*)(void))chacha20_poly1305_gettable_params }, 357 { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, 358 (void (*)(void))chacha20_poly1305_get_ctx_params }, 359 { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, 360 (void (*)(void))chacha20_poly1305_gettable_ctx_params }, 361 { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, 362 (void (*)(void))chacha20_poly1305_set_ctx_params }, 363 { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, 364 (void (*)(void))chacha20_poly1305_settable_ctx_params }, 365 OSSL_DISPATCH_END 366 }; 367 368