Home | History | Annotate | Line # | Download | only in ciphers
      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