1 /* 2 * Copyright 2019-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 /* 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 #define chacha20_poly1305_settable_ctx_params ossl_cipher_aead_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 int chacha20_poly1305_set_ctx_params(void *vctx, 162 const OSSL_PARAM params[]) 163 { 164 const OSSL_PARAM *p; 165 size_t len; 166 PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; 167 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 168 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->base.hw; 169 170 if (params == NULL) 171 return 1; 172 173 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); 174 if (p != NULL) { 175 if (!OSSL_PARAM_get_size_t(p, &len)) { 176 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 177 return 0; 178 } 179 if (len != CHACHA20_POLY1305_KEYLEN) { 180 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 181 return 0; 182 } 183 } 184 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); 185 if (p != NULL) { 186 if (!OSSL_PARAM_get_size_t(p, &len)) { 187 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 188 return 0; 189 } 190 if (len != CHACHA20_POLY1305_MAX_IVLEN) { 191 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 192 return 0; 193 } 194 } 195 196 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); 197 if (p != NULL) { 198 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 199 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 200 return 0; 201 } 202 if (p->data_size == 0 || p->data_size > POLY1305_BLOCK_SIZE) { 203 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH); 204 return 0; 205 } 206 if (p->data != NULL) { 207 if (ctx->base.enc) { 208 ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED); 209 return 0; 210 } 211 memcpy(ctx->tag, p->data, p->data_size); 212 } 213 ctx->tag_len = p->data_size; 214 } 215 216 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); 217 if (p != NULL) { 218 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 219 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 220 return 0; 221 } 222 len = hw->tls_init(&ctx->base, p->data, p->data_size); 223 if (len == 0) { 224 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA); 225 return 0; 226 } 227 ctx->tls_aad_pad_sz = len; 228 } 229 230 p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED); 231 if (p != NULL) { 232 if (p->data_type != OSSL_PARAM_OCTET_STRING) { 233 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); 234 return 0; 235 } 236 if (hw->tls_iv_set_fixed(&ctx->base, p->data, p->data_size) == 0) { 237 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 238 return 0; 239 } 240 } 241 /* ignore OSSL_CIPHER_PARAM_AEAD_MAC_KEY */ 242 return 1; 243 } 244 245 static int chacha20_poly1305_einit(void *vctx, const unsigned char *key, 246 size_t keylen, const unsigned char *iv, 247 size_t ivlen, const OSSL_PARAM params[]) 248 { 249 int ret; 250 251 /* The generic function checks for ossl_prov_is_running() */ 252 ret = ossl_cipher_generic_einit(vctx, key, keylen, iv, ivlen, NULL); 253 if (ret && iv != NULL) { 254 PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; 255 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 256 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; 257 258 hw->initiv(ctx); 259 } 260 if (ret && !chacha20_poly1305_set_ctx_params(vctx, params)) 261 ret = 0; 262 return ret; 263 } 264 265 static int chacha20_poly1305_dinit(void *vctx, const unsigned char *key, 266 size_t keylen, const unsigned char *iv, 267 size_t ivlen, const OSSL_PARAM params[]) 268 { 269 int ret; 270 271 /* The generic function checks for ossl_prov_is_running() */ 272 ret = ossl_cipher_generic_dinit(vctx, key, keylen, iv, ivlen, NULL); 273 if (ret && iv != NULL) { 274 PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; 275 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 276 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; 277 278 hw->initiv(ctx); 279 } 280 if (ret && !chacha20_poly1305_set_ctx_params(vctx, params)) 281 ret = 0; 282 return ret; 283 } 284 285 static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, 286 size_t *outl, size_t outsize, 287 const unsigned char *in, size_t inl) 288 { 289 PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; 290 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 291 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; 292 293 if (!ossl_prov_is_running()) 294 return 0; 295 296 if (inl == 0) { 297 *outl = 0; 298 return 1; 299 } 300 301 if (outsize < inl) { 302 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 303 return 0; 304 } 305 306 if (!hw->aead_cipher(ctx, out, outl, in, inl)) 307 return 0; 308 309 return 1; 310 } 311 312 static int chacha20_poly1305_final(void *vctx, unsigned char *out, size_t *outl, 313 size_t outsize) 314 { 315 PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; 316 PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = 317 (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; 318 319 if (!ossl_prov_is_running()) 320 return 0; 321 322 if (hw->aead_cipher(ctx, out, outl, NULL, 0) <= 0) 323 return 0; 324 325 *outl = 0; 326 return 1; 327 } 328 329 /* ossl_chacha20_ossl_poly1305_functions */ 330 const OSSL_DISPATCH ossl_chacha20_ossl_poly1305_functions[] = { 331 { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))chacha20_poly1305_newctx }, 332 { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))chacha20_poly1305_freectx }, 333 { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))chacha20_poly1305_dupctx }, 334 { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))chacha20_poly1305_einit }, 335 { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))chacha20_poly1305_dinit }, 336 { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))chacha20_poly1305_update }, 337 { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))chacha20_poly1305_final }, 338 { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))chacha20_poly1305_cipher }, 339 { OSSL_FUNC_CIPHER_GET_PARAMS, 340 (void (*)(void))chacha20_poly1305_get_params }, 341 { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, 342 (void (*)(void))chacha20_poly1305_gettable_params }, 343 { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, 344 (void (*)(void))chacha20_poly1305_get_ctx_params }, 345 { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, 346 (void (*)(void))chacha20_poly1305_gettable_ctx_params }, 347 { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, 348 (void (*)(void))chacha20_poly1305_set_ctx_params }, 349 { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, 350 (void (*)(void))chacha20_poly1305_settable_ctx_params }, 351 { 0, NULL } 352 }; 353 354