Path: blob/main/crypto/openssl/providers/implementations/ciphers/cipher_aes_ocb.c
48383 views
/*1* Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/*10* AES low level APIs are deprecated for public use, but still ok for internal11* use where we're using them to implement the higher level EVP interface, as is12* the case here.13*/14#include "internal/deprecated.h"1516#include <openssl/proverr.h>17#include "cipher_aes_ocb.h"18#include "prov/providercommon.h"19#include "prov/ciphercommon_aead.h"20#include "prov/implementations.h"2122#define AES_OCB_FLAGS AEAD_FLAGS2324#define OCB_DEFAULT_TAG_LEN 1625#define OCB_DEFAULT_IV_LEN 1226#define OCB_MIN_IV_LEN 127#define OCB_MAX_IV_LEN 152829PROV_CIPHER_FUNC(int, ocb_cipher, (PROV_AES_OCB_CTX *ctx,30const unsigned char *in, unsigned char *out,31size_t nextblock));32/* forward declarations */33static OSSL_FUNC_cipher_encrypt_init_fn aes_ocb_einit;34static OSSL_FUNC_cipher_decrypt_init_fn aes_ocb_dinit;35static OSSL_FUNC_cipher_update_fn aes_ocb_block_update;36static OSSL_FUNC_cipher_final_fn aes_ocb_block_final;37static OSSL_FUNC_cipher_cipher_fn aes_ocb_cipher;38static OSSL_FUNC_cipher_freectx_fn aes_ocb_freectx;39static OSSL_FUNC_cipher_dupctx_fn aes_ocb_dupctx;40static OSSL_FUNC_cipher_get_ctx_params_fn aes_ocb_get_ctx_params;41static OSSL_FUNC_cipher_set_ctx_params_fn aes_ocb_set_ctx_params;42static OSSL_FUNC_cipher_gettable_ctx_params_fn cipher_ocb_gettable_ctx_params;43static OSSL_FUNC_cipher_settable_ctx_params_fn cipher_ocb_settable_ctx_params;4445/*46* The following methods could be moved into PROV_AES_OCB_HW if47* multiple hardware implementations are ever needed.48*/49static ossl_inline int aes_generic_ocb_setiv(PROV_AES_OCB_CTX *ctx,50const unsigned char *iv,51size_t ivlen, size_t taglen)52{53return (CRYPTO_ocb128_setiv(&ctx->ocb, iv, ivlen, taglen) == 1);54}5556static ossl_inline int aes_generic_ocb_setaad(PROV_AES_OCB_CTX *ctx,57const unsigned char *aad,58size_t alen)59{60return CRYPTO_ocb128_aad(&ctx->ocb, aad, alen) == 1;61}6263static ossl_inline int aes_generic_ocb_gettag(PROV_AES_OCB_CTX *ctx,64unsigned char *tag, size_t tlen)65{66return CRYPTO_ocb128_tag(&ctx->ocb, tag, tlen) > 0;67}6869static ossl_inline int aes_generic_ocb_final(PROV_AES_OCB_CTX *ctx)70{71return (CRYPTO_ocb128_finish(&ctx->ocb, ctx->tag, ctx->taglen) == 0);72}7374static ossl_inline void aes_generic_ocb_cleanup(PROV_AES_OCB_CTX *ctx)75{76CRYPTO_ocb128_cleanup(&ctx->ocb);77}7879static ossl_inline int aes_generic_ocb_cipher(PROV_AES_OCB_CTX *ctx,80const unsigned char *in,81unsigned char *out, size_t len)82{83if (ctx->base.enc) {84if (!CRYPTO_ocb128_encrypt(&ctx->ocb, in, out, len))85return 0;86} else {87if (!CRYPTO_ocb128_decrypt(&ctx->ocb, in, out, len))88return 0;89}90return 1;91}9293static ossl_inline int aes_generic_ocb_copy_ctx(PROV_AES_OCB_CTX *dst,94PROV_AES_OCB_CTX *src)95{96return CRYPTO_ocb128_copy_ctx(&dst->ocb, &src->ocb,97&dst->ksenc.ks, &dst->ksdec.ks);98}99100/*-101* Provider dispatch functions102*/103static int aes_ocb_init(void *vctx, const unsigned char *key, size_t keylen,104const unsigned char *iv, size_t ivlen,105const OSSL_PARAM params[], int enc)106{107PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;108109if (!ossl_prov_is_running())110return 0;111112ctx->aad_buf_len = 0;113ctx->data_buf_len = 0;114ctx->base.enc = enc;115116if (iv != NULL) {117if (ivlen != ctx->base.ivlen) {118/* IV len must be 1 to 15 */119if (ivlen < OCB_MIN_IV_LEN || ivlen > OCB_MAX_IV_LEN) {120ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);121return 0;122}123ctx->base.ivlen = ivlen;124}125if (!ossl_cipher_generic_initiv(&ctx->base, iv, ivlen))126return 0;127ctx->iv_state = IV_STATE_BUFFERED;128}129if (key != NULL) {130if (keylen != ctx->base.keylen) {131ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);132return 0;133}134if (!ctx->base.hw->init(&ctx->base, key, keylen))135return 0;136}137return aes_ocb_set_ctx_params(ctx, params);138}139140static int aes_ocb_einit(void *vctx, const unsigned char *key, size_t keylen,141const unsigned char *iv, size_t ivlen,142const OSSL_PARAM params[])143{144return aes_ocb_init(vctx, key, keylen, iv, ivlen, params, 1);145}146147static int aes_ocb_dinit(void *vctx, const unsigned char *key, size_t keylen,148const unsigned char *iv, size_t ivlen,149const OSSL_PARAM params[])150{151return aes_ocb_init(vctx, key, keylen, iv, ivlen, params, 0);152}153154/*155* Because of the way OCB works, both the AAD and data are buffered in the156* same way. Only the last block can be a partial block.157*/158static int aes_ocb_block_update_internal(PROV_AES_OCB_CTX *ctx,159unsigned char *buf, size_t *bufsz,160unsigned char *out, size_t *outl,161size_t outsize, const unsigned char *in,162size_t inl, OSSL_ocb_cipher_fn ciph)163{164size_t nextblocks;165size_t outlint = 0;166167if (*bufsz != 0)168nextblocks = ossl_cipher_fillblock(buf, bufsz, AES_BLOCK_SIZE, &in, &inl);169else170nextblocks = inl & ~(AES_BLOCK_SIZE-1);171172if (*bufsz == AES_BLOCK_SIZE) {173if (outsize < AES_BLOCK_SIZE) {174ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);175return 0;176}177if (!ciph(ctx, buf, out, AES_BLOCK_SIZE)) {178ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);179return 0;180}181*bufsz = 0;182outlint = AES_BLOCK_SIZE;183if (out != NULL)184out += AES_BLOCK_SIZE;185}186if (nextblocks > 0) {187outlint += nextblocks;188if (outsize < outlint) {189ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);190return 0;191}192if (!ciph(ctx, in, out, nextblocks)) {193ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);194return 0;195}196in += nextblocks;197inl -= nextblocks;198}199if (inl != 0200&& !ossl_cipher_trailingdata(buf, bufsz, AES_BLOCK_SIZE, &in, &inl)) {201/* PROVerr already called */202return 0;203}204205*outl = outlint;206return inl == 0;207}208209/* A wrapper function that has the same signature as cipher */210static int cipher_updateaad(PROV_AES_OCB_CTX *ctx, const unsigned char *in,211unsigned char *out, size_t len)212{213return aes_generic_ocb_setaad(ctx, in, len);214}215216static int update_iv(PROV_AES_OCB_CTX *ctx)217{218if (ctx->iv_state == IV_STATE_FINISHED219|| ctx->iv_state == IV_STATE_UNINITIALISED)220return 0;221if (ctx->iv_state == IV_STATE_BUFFERED) {222if (!aes_generic_ocb_setiv(ctx, ctx->base.iv, ctx->base.ivlen,223ctx->taglen))224return 0;225ctx->iv_state = IV_STATE_COPIED;226}227return 1;228}229230static int aes_ocb_block_update(void *vctx, unsigned char *out, size_t *outl,231size_t outsize, const unsigned char *in,232size_t inl)233{234PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;235unsigned char *buf;236size_t *buflen;237OSSL_ocb_cipher_fn fn;238239if (!ctx->key_set || !update_iv(ctx))240return 0;241242if (inl == 0) {243*outl = 0;244return 1;245}246247/* Are we dealing with AAD or normal data here? */248if (out == NULL) {249buf = ctx->aad_buf;250buflen = &ctx->aad_buf_len;251fn = cipher_updateaad;252} else {253buf = ctx->data_buf;254buflen = &ctx->data_buf_len;255fn = aes_generic_ocb_cipher;256}257return aes_ocb_block_update_internal(ctx, buf, buflen, out, outl, outsize,258in, inl, fn);259}260261static int aes_ocb_block_final(void *vctx, unsigned char *out, size_t *outl,262size_t outsize)263{264PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;265266if (!ossl_prov_is_running())267return 0;268269/* If no block_update has run then the iv still needs to be set */270if (!ctx->key_set || !update_iv(ctx))271return 0;272273/*274* Empty the buffer of any partial block that we might have been provided,275* both for data and AAD276*/277*outl = 0;278if (ctx->data_buf_len > 0) {279if (!aes_generic_ocb_cipher(ctx, ctx->data_buf, out, ctx->data_buf_len))280return 0;281*outl = ctx->data_buf_len;282ctx->data_buf_len = 0;283}284if (ctx->aad_buf_len > 0) {285if (!aes_generic_ocb_setaad(ctx, ctx->aad_buf, ctx->aad_buf_len))286return 0;287ctx->aad_buf_len = 0;288}289if (ctx->base.enc) {290/* If encrypting then just get the tag */291if (!aes_generic_ocb_gettag(ctx, ctx->tag, ctx->taglen))292return 0;293} else {294/* If decrypting then verify */295if (ctx->taglen == 0)296return 0;297if (!aes_generic_ocb_final(ctx))298return 0;299}300/* Don't reuse the IV */301ctx->iv_state = IV_STATE_FINISHED;302return 1;303}304305static void *aes_ocb_newctx(void *provctx, size_t kbits, size_t blkbits,306size_t ivbits, unsigned int mode, uint64_t flags)307{308PROV_AES_OCB_CTX *ctx;309310if (!ossl_prov_is_running())311return NULL;312313ctx = OPENSSL_zalloc(sizeof(*ctx));314if (ctx != NULL) {315ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits, mode, flags,316ossl_prov_cipher_hw_aes_ocb(kbits), NULL);317ctx->taglen = OCB_DEFAULT_TAG_LEN;318}319return ctx;320}321322static void aes_ocb_freectx(void *vctx)323{324PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;325326if (ctx != NULL) {327aes_generic_ocb_cleanup(ctx);328ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx);329OPENSSL_clear_free(ctx, sizeof(*ctx));330}331}332333static void *aes_ocb_dupctx(void *vctx)334{335PROV_AES_OCB_CTX *in = (PROV_AES_OCB_CTX *)vctx;336PROV_AES_OCB_CTX *ret;337338if (!ossl_prov_is_running())339return NULL;340341ret = OPENSSL_malloc(sizeof(*ret));342if (ret == NULL)343return NULL;344*ret = *in;345if (!aes_generic_ocb_copy_ctx(ret, in)) {346OPENSSL_free(ret);347ret = NULL;348}349return ret;350}351352static int aes_ocb_set_ctx_params(void *vctx, const OSSL_PARAM params[])353{354PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;355const OSSL_PARAM *p;356size_t sz;357358if (ossl_param_is_empty(params))359return 1;360361p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG);362if (p != NULL) {363if (p->data_type != OSSL_PARAM_OCTET_STRING) {364ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);365return 0;366}367if (p->data == NULL) {368/* Tag len must be 0 to 16 */369if (p->data_size > OCB_MAX_TAG_LEN) {370ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH);371return 0;372}373ctx->taglen = p->data_size;374} else {375if (ctx->base.enc) {376ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);377return 0;378}379if (p->data_size != ctx->taglen) {380ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH);381return 0;382}383memcpy(ctx->tag, p->data, p->data_size);384}385}386p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN);387if (p != NULL) {388if (!OSSL_PARAM_get_size_t(p, &sz)) {389ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);390return 0;391}392/* IV len must be 1 to 15 */393if (sz < OCB_MIN_IV_LEN || sz > OCB_MAX_IV_LEN)394return 0;395if (ctx->base.ivlen != sz) {396ctx->base.ivlen = sz;397ctx->iv_state = IV_STATE_UNINITIALISED;398}399}400p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);401if (p != NULL) {402size_t keylen;403404if (!OSSL_PARAM_get_size_t(p, &keylen)) {405ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);406return 0;407}408if (ctx->base.keylen != keylen) {409ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);410return 0;411}412}413return 1;414}415416static int aes_ocb_get_ctx_params(void *vctx, OSSL_PARAM params[])417{418PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;419OSSL_PARAM *p;420421p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);422if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.ivlen)) {423ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);424return 0;425}426p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);427if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.keylen)) {428ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);429return 0;430}431p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN);432if (p != NULL) {433if (!OSSL_PARAM_set_size_t(p, ctx->taglen)) {434ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);435return 0;436}437}438439p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV);440if (p != NULL) {441if (ctx->base.ivlen > p->data_size) {442ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);443return 0;444}445if (!OSSL_PARAM_set_octet_string(p, ctx->base.oiv, ctx->base.ivlen)446&& !OSSL_PARAM_set_octet_ptr(p, &ctx->base.oiv, ctx->base.ivlen)) {447ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);448return 0;449}450}451p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV);452if (p != NULL) {453if (ctx->base.ivlen > p->data_size) {454ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);455return 0;456}457if (!OSSL_PARAM_set_octet_string(p, ctx->base.iv, ctx->base.ivlen)458&& !OSSL_PARAM_set_octet_ptr(p, &ctx->base.iv, ctx->base.ivlen)) {459ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);460return 0;461}462}463p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG);464if (p != NULL) {465if (p->data_type != OSSL_PARAM_OCTET_STRING) {466ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);467return 0;468}469if (!ctx->base.enc || p->data_size != ctx->taglen) {470ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH);471return 0;472}473memcpy(p->data, ctx->tag, ctx->taglen);474}475return 1;476}477478static const OSSL_PARAM cipher_ocb_known_gettable_ctx_params[] = {479OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),480OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),481OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL),482OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0),483OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_UPDATED_IV, NULL, 0),484OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),485OSSL_PARAM_END486};487static const OSSL_PARAM *cipher_ocb_gettable_ctx_params(ossl_unused void *cctx,488ossl_unused void *p_ctx)489{490return cipher_ocb_known_gettable_ctx_params;491}492493static const OSSL_PARAM cipher_ocb_known_settable_ctx_params[] = {494OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),495OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, NULL),496OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),497OSSL_PARAM_END498};499static const OSSL_PARAM *cipher_ocb_settable_ctx_params(ossl_unused void *cctx,500ossl_unused void *p_ctx)501{502return cipher_ocb_known_settable_ctx_params;503}504505static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl,506size_t outsize, const unsigned char *in, size_t inl)507{508PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;509510if (!ossl_prov_is_running())511return 0;512513if (outsize < inl) {514ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);515return 0;516}517518if (!aes_generic_ocb_cipher(ctx, in, out, inl)) {519ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);520return 0;521}522523*outl = inl;524return 1;525}526527#define IMPLEMENT_cipher(mode, UCMODE, flags, kbits, blkbits, ivbits) \528static OSSL_FUNC_cipher_get_params_fn aes_##kbits##_##mode##_get_params; \529static int aes_##kbits##_##mode##_get_params(OSSL_PARAM params[]) \530{ \531return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \532flags, kbits, blkbits, ivbits); \533} \534static OSSL_FUNC_cipher_newctx_fn aes_##kbits##_##mode##_newctx; \535static void *aes_##kbits##_##mode##_newctx(void *provctx) \536{ \537return aes_##mode##_newctx(provctx, kbits, blkbits, ivbits, \538EVP_CIPH_##UCMODE##_MODE, flags); \539} \540const OSSL_DISPATCH ossl_##aes##kbits##mode##_functions[] = { \541{ OSSL_FUNC_CIPHER_NEWCTX, \542(void (*)(void))aes_##kbits##_##mode##_newctx }, \543{ OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_##mode##_einit }, \544{ OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_##mode##_dinit }, \545{ OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_##mode##_block_update }, \546{ OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_##mode##_block_final }, \547{ OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))aes_ocb_cipher }, \548{ OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_##mode##_freectx }, \549{ OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))aes_##mode##_dupctx }, \550{ OSSL_FUNC_CIPHER_GET_PARAMS, \551(void (*)(void))aes_##kbits##_##mode##_get_params }, \552{ OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \553(void (*)(void))aes_##mode##_get_ctx_params }, \554{ OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \555(void (*)(void))aes_##mode##_set_ctx_params }, \556{ OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \557(void (*)(void))ossl_cipher_generic_gettable_params }, \558{ OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \559(void (*)(void))cipher_ocb_gettable_ctx_params }, \560{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \561(void (*)(void))cipher_ocb_settable_ctx_params }, \562OSSL_DISPATCH_END \563}564565IMPLEMENT_cipher(ocb, OCB, AES_OCB_FLAGS, 256, 128, OCB_DEFAULT_IV_LEN * 8);566IMPLEMENT_cipher(ocb, OCB, AES_OCB_FLAGS, 192, 128, OCB_DEFAULT_IV_LEN * 8);567IMPLEMENT_cipher(ocb, OCB, AES_OCB_FLAGS, 128, 128, OCB_DEFAULT_IV_LEN * 8);568569570