1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <openssl/core_names.h> 11e1051a39Sopenharmony_ci#include <openssl/bio.h> 12e1051a39Sopenharmony_ci#include <openssl/encoder.h> 13e1051a39Sopenharmony_ci#include <openssl/buffer.h> 14e1051a39Sopenharmony_ci#include <openssl/params.h> 15e1051a39Sopenharmony_ci#include <openssl/provider.h> 16e1051a39Sopenharmony_ci#include <openssl/trace.h> 17e1051a39Sopenharmony_ci#include "internal/bio.h" 18e1051a39Sopenharmony_ci#include "internal/provider.h" 19e1051a39Sopenharmony_ci#include "encoder_local.h" 20e1051a39Sopenharmony_ci 21e1051a39Sopenharmony_cistruct encoder_process_data_st { 22e1051a39Sopenharmony_ci OSSL_ENCODER_CTX *ctx; 23e1051a39Sopenharmony_ci 24e1051a39Sopenharmony_ci /* Current BIO */ 25e1051a39Sopenharmony_ci BIO *bio; 26e1051a39Sopenharmony_ci 27e1051a39Sopenharmony_ci /* Index of the current encoder instance to be processed */ 28e1051a39Sopenharmony_ci int current_encoder_inst_index; 29e1051a39Sopenharmony_ci 30e1051a39Sopenharmony_ci /* Processing data passed down through recursion */ 31e1051a39Sopenharmony_ci int level; /* Recursion level */ 32e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE *next_encoder_inst; 33e1051a39Sopenharmony_ci int count_output_structure; 34e1051a39Sopenharmony_ci 35e1051a39Sopenharmony_ci /* Processing data passed up through recursion */ 36e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE *prev_encoder_inst; 37e1051a39Sopenharmony_ci unsigned char *running_output; 38e1051a39Sopenharmony_ci size_t running_output_length; 39e1051a39Sopenharmony_ci /* Data type = the name of the first succeeding encoder implementation */ 40e1051a39Sopenharmony_ci const char *data_type; 41e1051a39Sopenharmony_ci}; 42e1051a39Sopenharmony_ci 43e1051a39Sopenharmony_cistatic int encoder_process(struct encoder_process_data_st *data); 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_ciint OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out) 46e1051a39Sopenharmony_ci{ 47e1051a39Sopenharmony_ci struct encoder_process_data_st data; 48e1051a39Sopenharmony_ci 49e1051a39Sopenharmony_ci memset(&data, 0, sizeof(data)); 50e1051a39Sopenharmony_ci data.ctx = ctx; 51e1051a39Sopenharmony_ci data.bio = out; 52e1051a39Sopenharmony_ci data.current_encoder_inst_index = OSSL_ENCODER_CTX_get_num_encoders(ctx); 53e1051a39Sopenharmony_ci 54e1051a39Sopenharmony_ci if (data.current_encoder_inst_index == 0) { 55e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_ENCODER_NOT_FOUND, 56e1051a39Sopenharmony_ci "No encoders were found. For standard encoders you need " 57e1051a39Sopenharmony_ci "at least one of the default or base providers " 58e1051a39Sopenharmony_ci "available. Did you forget to load them?"); 59e1051a39Sopenharmony_ci return 0; 60e1051a39Sopenharmony_ci } 61e1051a39Sopenharmony_ci 62e1051a39Sopenharmony_ci return encoder_process(&data) > 0; 63e1051a39Sopenharmony_ci} 64e1051a39Sopenharmony_ci 65e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO 66e1051a39Sopenharmony_cistatic BIO *bio_from_file(FILE *fp) 67e1051a39Sopenharmony_ci{ 68e1051a39Sopenharmony_ci BIO *b; 69e1051a39Sopenharmony_ci 70e1051a39Sopenharmony_ci if ((b = BIO_new(BIO_s_file())) == NULL) { 71e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_BUF_LIB); 72e1051a39Sopenharmony_ci return NULL; 73e1051a39Sopenharmony_ci } 74e1051a39Sopenharmony_ci BIO_set_fp(b, fp, BIO_NOCLOSE); 75e1051a39Sopenharmony_ci return b; 76e1051a39Sopenharmony_ci} 77e1051a39Sopenharmony_ci 78e1051a39Sopenharmony_ciint OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp) 79e1051a39Sopenharmony_ci{ 80e1051a39Sopenharmony_ci BIO *b = bio_from_file(fp); 81e1051a39Sopenharmony_ci int ret = 0; 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci if (b != NULL) 84e1051a39Sopenharmony_ci ret = OSSL_ENCODER_to_bio(ctx, b); 85e1051a39Sopenharmony_ci 86e1051a39Sopenharmony_ci BIO_free(b); 87e1051a39Sopenharmony_ci return ret; 88e1051a39Sopenharmony_ci} 89e1051a39Sopenharmony_ci#endif 90e1051a39Sopenharmony_ci 91e1051a39Sopenharmony_ciint OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata, 92e1051a39Sopenharmony_ci size_t *pdata_len) 93e1051a39Sopenharmony_ci{ 94e1051a39Sopenharmony_ci BIO *out; 95e1051a39Sopenharmony_ci BUF_MEM *buf = NULL; 96e1051a39Sopenharmony_ci int ret = 0; 97e1051a39Sopenharmony_ci 98e1051a39Sopenharmony_ci if (pdata_len == NULL) { 99e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); 100e1051a39Sopenharmony_ci return 0; 101e1051a39Sopenharmony_ci } 102e1051a39Sopenharmony_ci 103e1051a39Sopenharmony_ci out = BIO_new(BIO_s_mem()); 104e1051a39Sopenharmony_ci 105e1051a39Sopenharmony_ci if (out != NULL 106e1051a39Sopenharmony_ci && OSSL_ENCODER_to_bio(ctx, out) 107e1051a39Sopenharmony_ci && BIO_get_mem_ptr(out, &buf) > 0) { 108e1051a39Sopenharmony_ci ret = 1; /* Hope for the best. A too small buffer will clear this */ 109e1051a39Sopenharmony_ci 110e1051a39Sopenharmony_ci if (pdata != NULL && *pdata != NULL) { 111e1051a39Sopenharmony_ci if (*pdata_len < buf->length) 112e1051a39Sopenharmony_ci /* 113e1051a39Sopenharmony_ci * It's tempting to do |*pdata_len = (size_t)buf->length| 114e1051a39Sopenharmony_ci * However, it's believed to be confusing more than helpful, 115e1051a39Sopenharmony_ci * so we don't. 116e1051a39Sopenharmony_ci */ 117e1051a39Sopenharmony_ci ret = 0; 118e1051a39Sopenharmony_ci else 119e1051a39Sopenharmony_ci *pdata_len -= buf->length; 120e1051a39Sopenharmony_ci } else { 121e1051a39Sopenharmony_ci /* The buffer with the right size is already allocated for us */ 122e1051a39Sopenharmony_ci *pdata_len = (size_t)buf->length; 123e1051a39Sopenharmony_ci } 124e1051a39Sopenharmony_ci 125e1051a39Sopenharmony_ci if (ret) { 126e1051a39Sopenharmony_ci if (pdata != NULL) { 127e1051a39Sopenharmony_ci if (*pdata != NULL) { 128e1051a39Sopenharmony_ci memcpy(*pdata, buf->data, buf->length); 129e1051a39Sopenharmony_ci *pdata += buf->length; 130e1051a39Sopenharmony_ci } else { 131e1051a39Sopenharmony_ci /* In this case, we steal the data from BIO_s_mem() */ 132e1051a39Sopenharmony_ci *pdata = (unsigned char *)buf->data; 133e1051a39Sopenharmony_ci buf->data = NULL; 134e1051a39Sopenharmony_ci } 135e1051a39Sopenharmony_ci } 136e1051a39Sopenharmony_ci } 137e1051a39Sopenharmony_ci } 138e1051a39Sopenharmony_ci BIO_free(out); 139e1051a39Sopenharmony_ci return ret; 140e1051a39Sopenharmony_ci} 141e1051a39Sopenharmony_ci 142e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection) 143e1051a39Sopenharmony_ci{ 144e1051a39Sopenharmony_ci if (!ossl_assert(ctx != NULL)) { 145e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); 146e1051a39Sopenharmony_ci return 0; 147e1051a39Sopenharmony_ci } 148e1051a39Sopenharmony_ci 149e1051a39Sopenharmony_ci if (!ossl_assert(selection != 0)) { 150e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT); 151e1051a39Sopenharmony_ci return 0; 152e1051a39Sopenharmony_ci } 153e1051a39Sopenharmony_ci 154e1051a39Sopenharmony_ci ctx->selection = selection; 155e1051a39Sopenharmony_ci return 1; 156e1051a39Sopenharmony_ci} 157e1051a39Sopenharmony_ci 158e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx, 159e1051a39Sopenharmony_ci const char *output_type) 160e1051a39Sopenharmony_ci{ 161e1051a39Sopenharmony_ci if (!ossl_assert(ctx != NULL) || !ossl_assert(output_type != NULL)) { 162e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); 163e1051a39Sopenharmony_ci return 0; 164e1051a39Sopenharmony_ci } 165e1051a39Sopenharmony_ci 166e1051a39Sopenharmony_ci ctx->output_type = output_type; 167e1051a39Sopenharmony_ci return 1; 168e1051a39Sopenharmony_ci} 169e1051a39Sopenharmony_ci 170e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX *ctx, 171e1051a39Sopenharmony_ci const char *output_structure) 172e1051a39Sopenharmony_ci{ 173e1051a39Sopenharmony_ci if (!ossl_assert(ctx != NULL) || !ossl_assert(output_structure != NULL)) { 174e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); 175e1051a39Sopenharmony_ci return 0; 176e1051a39Sopenharmony_ci } 177e1051a39Sopenharmony_ci 178e1051a39Sopenharmony_ci ctx->output_structure = output_structure; 179e1051a39Sopenharmony_ci return 1; 180e1051a39Sopenharmony_ci} 181e1051a39Sopenharmony_ci 182e1051a39Sopenharmony_cistatic OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder, 183e1051a39Sopenharmony_ci void *encoderctx) 184e1051a39Sopenharmony_ci{ 185e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE *encoder_inst = NULL; 186e1051a39Sopenharmony_ci const OSSL_PROVIDER *prov; 187e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx; 188e1051a39Sopenharmony_ci const OSSL_PROPERTY_LIST *props; 189e1051a39Sopenharmony_ci const OSSL_PROPERTY_DEFINITION *prop; 190e1051a39Sopenharmony_ci 191e1051a39Sopenharmony_ci if (!ossl_assert(encoder != NULL)) { 192e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); 193e1051a39Sopenharmony_ci return 0; 194e1051a39Sopenharmony_ci } 195e1051a39Sopenharmony_ci 196e1051a39Sopenharmony_ci if ((encoder_inst = OPENSSL_zalloc(sizeof(*encoder_inst))) == NULL) { 197e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE); 198e1051a39Sopenharmony_ci return 0; 199e1051a39Sopenharmony_ci } 200e1051a39Sopenharmony_ci 201e1051a39Sopenharmony_ci if (!OSSL_ENCODER_up_ref(encoder)) { 202e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR); 203e1051a39Sopenharmony_ci goto err; 204e1051a39Sopenharmony_ci } 205e1051a39Sopenharmony_ci 206e1051a39Sopenharmony_ci prov = OSSL_ENCODER_get0_provider(encoder); 207e1051a39Sopenharmony_ci libctx = ossl_provider_libctx(prov); 208e1051a39Sopenharmony_ci props = ossl_encoder_parsed_properties(encoder); 209e1051a39Sopenharmony_ci if (props == NULL) { 210e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROPERTY_DEFINITION, 211e1051a39Sopenharmony_ci "there are no property definitions with encoder %s", 212e1051a39Sopenharmony_ci OSSL_ENCODER_get0_name(encoder)); 213e1051a39Sopenharmony_ci goto err; 214e1051a39Sopenharmony_ci } 215e1051a39Sopenharmony_ci 216e1051a39Sopenharmony_ci /* The "output" property is mandatory */ 217e1051a39Sopenharmony_ci prop = ossl_property_find_property(props, libctx, "output"); 218e1051a39Sopenharmony_ci encoder_inst->output_type = ossl_property_get_string_value(libctx, prop); 219e1051a39Sopenharmony_ci if (encoder_inst->output_type == NULL) { 220e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROPERTY_DEFINITION, 221e1051a39Sopenharmony_ci "the mandatory 'output' property is missing " 222e1051a39Sopenharmony_ci "for encoder %s (properties: %s)", 223e1051a39Sopenharmony_ci OSSL_ENCODER_get0_name(encoder), 224e1051a39Sopenharmony_ci OSSL_ENCODER_get0_properties(encoder)); 225e1051a39Sopenharmony_ci goto err; 226e1051a39Sopenharmony_ci } 227e1051a39Sopenharmony_ci 228e1051a39Sopenharmony_ci /* The "structure" property is optional */ 229e1051a39Sopenharmony_ci prop = ossl_property_find_property(props, libctx, "structure"); 230e1051a39Sopenharmony_ci if (prop != NULL) 231e1051a39Sopenharmony_ci encoder_inst->output_structure 232e1051a39Sopenharmony_ci = ossl_property_get_string_value(libctx, prop); 233e1051a39Sopenharmony_ci 234e1051a39Sopenharmony_ci encoder_inst->encoder = encoder; 235e1051a39Sopenharmony_ci encoder_inst->encoderctx = encoderctx; 236e1051a39Sopenharmony_ci return encoder_inst; 237e1051a39Sopenharmony_ci err: 238e1051a39Sopenharmony_ci ossl_encoder_instance_free(encoder_inst); 239e1051a39Sopenharmony_ci return NULL; 240e1051a39Sopenharmony_ci} 241e1051a39Sopenharmony_ci 242e1051a39Sopenharmony_civoid ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst) 243e1051a39Sopenharmony_ci{ 244e1051a39Sopenharmony_ci if (encoder_inst != NULL) { 245e1051a39Sopenharmony_ci if (encoder_inst->encoder != NULL) 246e1051a39Sopenharmony_ci encoder_inst->encoder->freectx(encoder_inst->encoderctx); 247e1051a39Sopenharmony_ci encoder_inst->encoderctx = NULL; 248e1051a39Sopenharmony_ci OSSL_ENCODER_free(encoder_inst->encoder); 249e1051a39Sopenharmony_ci encoder_inst->encoder = NULL; 250e1051a39Sopenharmony_ci OPENSSL_free(encoder_inst); 251e1051a39Sopenharmony_ci } 252e1051a39Sopenharmony_ci} 253e1051a39Sopenharmony_ci 254e1051a39Sopenharmony_cistatic int ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX *ctx, 255e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE *ei) 256e1051a39Sopenharmony_ci{ 257e1051a39Sopenharmony_ci int ok; 258e1051a39Sopenharmony_ci 259e1051a39Sopenharmony_ci if (ctx->encoder_insts == NULL 260e1051a39Sopenharmony_ci && (ctx->encoder_insts = 261e1051a39Sopenharmony_ci sk_OSSL_ENCODER_INSTANCE_new_null()) == NULL) { 262e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE); 263e1051a39Sopenharmony_ci return 0; 264e1051a39Sopenharmony_ci } 265e1051a39Sopenharmony_ci 266e1051a39Sopenharmony_ci ok = (sk_OSSL_ENCODER_INSTANCE_push(ctx->encoder_insts, ei) > 0); 267e1051a39Sopenharmony_ci if (ok) { 268e1051a39Sopenharmony_ci OSSL_TRACE_BEGIN(ENCODER) { 269e1051a39Sopenharmony_ci BIO_printf(trc_out, 270e1051a39Sopenharmony_ci "(ctx %p) Added encoder instance %p (encoder %p):\n" 271e1051a39Sopenharmony_ci " %s with %s\n", 272e1051a39Sopenharmony_ci (void *)ctx, (void *)ei, (void *)ei->encoder, 273e1051a39Sopenharmony_ci OSSL_ENCODER_get0_name(ei->encoder), 274e1051a39Sopenharmony_ci OSSL_ENCODER_get0_properties(ei->encoder)); 275e1051a39Sopenharmony_ci } OSSL_TRACE_END(ENCODER); 276e1051a39Sopenharmony_ci } 277e1051a39Sopenharmony_ci return ok; 278e1051a39Sopenharmony_ci} 279e1051a39Sopenharmony_ci 280e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder) 281e1051a39Sopenharmony_ci{ 282e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE *encoder_inst = NULL; 283e1051a39Sopenharmony_ci const OSSL_PROVIDER *prov = NULL; 284e1051a39Sopenharmony_ci void *encoderctx = NULL; 285e1051a39Sopenharmony_ci void *provctx = NULL; 286e1051a39Sopenharmony_ci 287e1051a39Sopenharmony_ci if (!ossl_assert(ctx != NULL) || !ossl_assert(encoder != NULL)) { 288e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); 289e1051a39Sopenharmony_ci return 0; 290e1051a39Sopenharmony_ci } 291e1051a39Sopenharmony_ci 292e1051a39Sopenharmony_ci prov = OSSL_ENCODER_get0_provider(encoder); 293e1051a39Sopenharmony_ci provctx = OSSL_PROVIDER_get0_provider_ctx(prov); 294e1051a39Sopenharmony_ci 295e1051a39Sopenharmony_ci if ((encoderctx = encoder->newctx(provctx)) == NULL 296e1051a39Sopenharmony_ci || (encoder_inst = 297e1051a39Sopenharmony_ci ossl_encoder_instance_new(encoder, encoderctx)) == NULL) 298e1051a39Sopenharmony_ci goto err; 299e1051a39Sopenharmony_ci /* Avoid double free of encoderctx on further errors */ 300e1051a39Sopenharmony_ci encoderctx = NULL; 301e1051a39Sopenharmony_ci 302e1051a39Sopenharmony_ci if (!ossl_encoder_ctx_add_encoder_inst(ctx, encoder_inst)) 303e1051a39Sopenharmony_ci goto err; 304e1051a39Sopenharmony_ci 305e1051a39Sopenharmony_ci return 1; 306e1051a39Sopenharmony_ci err: 307e1051a39Sopenharmony_ci ossl_encoder_instance_free(encoder_inst); 308e1051a39Sopenharmony_ci if (encoderctx != NULL) 309e1051a39Sopenharmony_ci encoder->freectx(encoderctx); 310e1051a39Sopenharmony_ci return 0; 311e1051a39Sopenharmony_ci} 312e1051a39Sopenharmony_ci 313e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx, 314e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx, const char *propq) 315e1051a39Sopenharmony_ci{ 316e1051a39Sopenharmony_ci return 1; 317e1051a39Sopenharmony_ci} 318e1051a39Sopenharmony_ci 319e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx) 320e1051a39Sopenharmony_ci{ 321e1051a39Sopenharmony_ci if (ctx == NULL || ctx->encoder_insts == NULL) 322e1051a39Sopenharmony_ci return 0; 323e1051a39Sopenharmony_ci return sk_OSSL_ENCODER_INSTANCE_num(ctx->encoder_insts); 324e1051a39Sopenharmony_ci} 325e1051a39Sopenharmony_ci 326e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx, 327e1051a39Sopenharmony_ci OSSL_ENCODER_CONSTRUCT *construct) 328e1051a39Sopenharmony_ci{ 329e1051a39Sopenharmony_ci if (!ossl_assert(ctx != NULL)) { 330e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); 331e1051a39Sopenharmony_ci return 0; 332e1051a39Sopenharmony_ci } 333e1051a39Sopenharmony_ci ctx->construct = construct; 334e1051a39Sopenharmony_ci return 1; 335e1051a39Sopenharmony_ci} 336e1051a39Sopenharmony_ci 337e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx, 338e1051a39Sopenharmony_ci void *construct_data) 339e1051a39Sopenharmony_ci{ 340e1051a39Sopenharmony_ci if (!ossl_assert(ctx != NULL)) { 341e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); 342e1051a39Sopenharmony_ci return 0; 343e1051a39Sopenharmony_ci } 344e1051a39Sopenharmony_ci ctx->construct_data = construct_data; 345e1051a39Sopenharmony_ci return 1; 346e1051a39Sopenharmony_ci} 347e1051a39Sopenharmony_ci 348e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx, 349e1051a39Sopenharmony_ci OSSL_ENCODER_CLEANUP *cleanup) 350e1051a39Sopenharmony_ci{ 351e1051a39Sopenharmony_ci if (!ossl_assert(ctx != NULL)) { 352e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); 353e1051a39Sopenharmony_ci return 0; 354e1051a39Sopenharmony_ci } 355e1051a39Sopenharmony_ci ctx->cleanup = cleanup; 356e1051a39Sopenharmony_ci return 1; 357e1051a39Sopenharmony_ci} 358e1051a39Sopenharmony_ci 359e1051a39Sopenharmony_ciOSSL_ENCODER * 360e1051a39Sopenharmony_ciOSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst) 361e1051a39Sopenharmony_ci{ 362e1051a39Sopenharmony_ci if (encoder_inst == NULL) 363e1051a39Sopenharmony_ci return NULL; 364e1051a39Sopenharmony_ci return encoder_inst->encoder; 365e1051a39Sopenharmony_ci} 366e1051a39Sopenharmony_ci 367e1051a39Sopenharmony_civoid * 368e1051a39Sopenharmony_ciOSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst) 369e1051a39Sopenharmony_ci{ 370e1051a39Sopenharmony_ci if (encoder_inst == NULL) 371e1051a39Sopenharmony_ci return NULL; 372e1051a39Sopenharmony_ci return encoder_inst->encoderctx; 373e1051a39Sopenharmony_ci} 374e1051a39Sopenharmony_ci 375e1051a39Sopenharmony_ciconst char * 376e1051a39Sopenharmony_ciOSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst) 377e1051a39Sopenharmony_ci{ 378e1051a39Sopenharmony_ci if (encoder_inst == NULL) 379e1051a39Sopenharmony_ci return NULL; 380e1051a39Sopenharmony_ci return encoder_inst->output_type; 381e1051a39Sopenharmony_ci} 382e1051a39Sopenharmony_ci 383e1051a39Sopenharmony_ciconst char * 384e1051a39Sopenharmony_ciOSSL_ENCODER_INSTANCE_get_output_structure(OSSL_ENCODER_INSTANCE *encoder_inst) 385e1051a39Sopenharmony_ci{ 386e1051a39Sopenharmony_ci if (encoder_inst == NULL) 387e1051a39Sopenharmony_ci return NULL; 388e1051a39Sopenharmony_ci return encoder_inst->output_structure; 389e1051a39Sopenharmony_ci} 390e1051a39Sopenharmony_ci 391e1051a39Sopenharmony_cistatic int encoder_process(struct encoder_process_data_st *data) 392e1051a39Sopenharmony_ci{ 393e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE *current_encoder_inst = NULL; 394e1051a39Sopenharmony_ci OSSL_ENCODER *current_encoder = NULL; 395e1051a39Sopenharmony_ci OSSL_ENCODER_CTX *current_encoder_ctx = NULL; 396e1051a39Sopenharmony_ci BIO *allocated_out = NULL; 397e1051a39Sopenharmony_ci const void *original_data = NULL; 398e1051a39Sopenharmony_ci OSSL_PARAM abstract[10]; 399e1051a39Sopenharmony_ci const OSSL_PARAM *current_abstract = NULL; 400e1051a39Sopenharmony_ci int i; 401e1051a39Sopenharmony_ci int ok = -1; /* -1 signifies that the lookup loop gave nothing */ 402e1051a39Sopenharmony_ci int top = 0; 403e1051a39Sopenharmony_ci 404e1051a39Sopenharmony_ci if (data->next_encoder_inst == NULL) { 405e1051a39Sopenharmony_ci /* First iteration, where we prepare for what is to come */ 406e1051a39Sopenharmony_ci 407e1051a39Sopenharmony_ci data->count_output_structure = 408e1051a39Sopenharmony_ci data->ctx->output_structure == NULL ? -1 : 0; 409e1051a39Sopenharmony_ci top = 1; 410e1051a39Sopenharmony_ci } 411e1051a39Sopenharmony_ci 412e1051a39Sopenharmony_ci for (i = data->current_encoder_inst_index; i-- > 0;) { 413e1051a39Sopenharmony_ci OSSL_ENCODER *next_encoder = NULL; 414e1051a39Sopenharmony_ci const char *current_output_type; 415e1051a39Sopenharmony_ci const char *current_output_structure; 416e1051a39Sopenharmony_ci struct encoder_process_data_st new_data; 417e1051a39Sopenharmony_ci 418e1051a39Sopenharmony_ci if (!top) 419e1051a39Sopenharmony_ci next_encoder = 420e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE_get_encoder(data->next_encoder_inst); 421e1051a39Sopenharmony_ci 422e1051a39Sopenharmony_ci current_encoder_inst = 423e1051a39Sopenharmony_ci sk_OSSL_ENCODER_INSTANCE_value(data->ctx->encoder_insts, i); 424e1051a39Sopenharmony_ci current_encoder = 425e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE_get_encoder(current_encoder_inst); 426e1051a39Sopenharmony_ci current_encoder_ctx = 427e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE_get_encoder_ctx(current_encoder_inst); 428e1051a39Sopenharmony_ci current_output_type = 429e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE_get_output_type(current_encoder_inst); 430e1051a39Sopenharmony_ci current_output_structure = 431e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE_get_output_structure(current_encoder_inst); 432e1051a39Sopenharmony_ci memset(&new_data, 0, sizeof(new_data)); 433e1051a39Sopenharmony_ci new_data.ctx = data->ctx; 434e1051a39Sopenharmony_ci new_data.current_encoder_inst_index = i; 435e1051a39Sopenharmony_ci new_data.next_encoder_inst = current_encoder_inst; 436e1051a39Sopenharmony_ci new_data.count_output_structure = data->count_output_structure; 437e1051a39Sopenharmony_ci new_data.level = data->level + 1; 438e1051a39Sopenharmony_ci 439e1051a39Sopenharmony_ci OSSL_TRACE_BEGIN(ENCODER) { 440e1051a39Sopenharmony_ci BIO_printf(trc_out, 441e1051a39Sopenharmony_ci "[%d] (ctx %p) Considering encoder instance %p (encoder %p)\n", 442e1051a39Sopenharmony_ci data->level, (void *)data->ctx, 443e1051a39Sopenharmony_ci (void *)current_encoder_inst, (void *)current_encoder); 444e1051a39Sopenharmony_ci } OSSL_TRACE_END(ENCODER); 445e1051a39Sopenharmony_ci 446e1051a39Sopenharmony_ci /* 447e1051a39Sopenharmony_ci * If this is the top call, we check if the output type of the current 448e1051a39Sopenharmony_ci * encoder matches the desired output type. 449e1051a39Sopenharmony_ci * If this isn't the top call, i.e. this is deeper in the recursion, 450e1051a39Sopenharmony_ci * we instead check if the output type of the current encoder matches 451e1051a39Sopenharmony_ci * the name of the next encoder (the one found by the parent call). 452e1051a39Sopenharmony_ci */ 453e1051a39Sopenharmony_ci if (top) { 454e1051a39Sopenharmony_ci if (data->ctx->output_type != NULL 455e1051a39Sopenharmony_ci && OPENSSL_strcasecmp(current_output_type, 456e1051a39Sopenharmony_ci data->ctx->output_type) != 0) { 457e1051a39Sopenharmony_ci OSSL_TRACE_BEGIN(ENCODER) { 458e1051a39Sopenharmony_ci BIO_printf(trc_out, 459e1051a39Sopenharmony_ci "[%d] Skipping because current encoder output type (%s) != desired output type (%s)\n", 460e1051a39Sopenharmony_ci data->level, 461e1051a39Sopenharmony_ci current_output_type, data->ctx->output_type); 462e1051a39Sopenharmony_ci } OSSL_TRACE_END(ENCODER); 463e1051a39Sopenharmony_ci continue; 464e1051a39Sopenharmony_ci } 465e1051a39Sopenharmony_ci } else { 466e1051a39Sopenharmony_ci if (!OSSL_ENCODER_is_a(next_encoder, current_output_type)) { 467e1051a39Sopenharmony_ci OSSL_TRACE_BEGIN(ENCODER) { 468e1051a39Sopenharmony_ci BIO_printf(trc_out, 469e1051a39Sopenharmony_ci "[%d] Skipping because current encoder output type (%s) != name of encoder %p\n", 470e1051a39Sopenharmony_ci data->level, 471e1051a39Sopenharmony_ci current_output_type, (void *)next_encoder); 472e1051a39Sopenharmony_ci } OSSL_TRACE_END(ENCODER); 473e1051a39Sopenharmony_ci continue; 474e1051a39Sopenharmony_ci } 475e1051a39Sopenharmony_ci } 476e1051a39Sopenharmony_ci 477e1051a39Sopenharmony_ci /* 478e1051a39Sopenharmony_ci * If the caller and the current encoder specify an output structure, 479e1051a39Sopenharmony_ci * Check if they match. If they do, count the match, otherwise skip 480e1051a39Sopenharmony_ci * the current encoder. 481e1051a39Sopenharmony_ci */ 482e1051a39Sopenharmony_ci if (data->ctx->output_structure != NULL 483e1051a39Sopenharmony_ci && current_output_structure != NULL) { 484e1051a39Sopenharmony_ci if (OPENSSL_strcasecmp(data->ctx->output_structure, 485e1051a39Sopenharmony_ci current_output_structure) != 0) { 486e1051a39Sopenharmony_ci OSSL_TRACE_BEGIN(ENCODER) { 487e1051a39Sopenharmony_ci BIO_printf(trc_out, 488e1051a39Sopenharmony_ci "[%d] Skipping because current encoder output structure (%s) != ctx output structure (%s)\n", 489e1051a39Sopenharmony_ci data->level, 490e1051a39Sopenharmony_ci current_output_structure, 491e1051a39Sopenharmony_ci data->ctx->output_structure); 492e1051a39Sopenharmony_ci } OSSL_TRACE_END(ENCODER); 493e1051a39Sopenharmony_ci continue; 494e1051a39Sopenharmony_ci } 495e1051a39Sopenharmony_ci 496e1051a39Sopenharmony_ci data->count_output_structure++; 497e1051a39Sopenharmony_ci } 498e1051a39Sopenharmony_ci 499e1051a39Sopenharmony_ci /* 500e1051a39Sopenharmony_ci * Recurse to process the encoder implementations before the current 501e1051a39Sopenharmony_ci * one. 502e1051a39Sopenharmony_ci */ 503e1051a39Sopenharmony_ci ok = encoder_process(&new_data); 504e1051a39Sopenharmony_ci 505e1051a39Sopenharmony_ci data->prev_encoder_inst = new_data.prev_encoder_inst; 506e1051a39Sopenharmony_ci data->running_output = new_data.running_output; 507e1051a39Sopenharmony_ci data->running_output_length = new_data.running_output_length; 508e1051a39Sopenharmony_ci 509e1051a39Sopenharmony_ci /* 510e1051a39Sopenharmony_ci * ok == -1 means that the recursion call above gave no further 511e1051a39Sopenharmony_ci * encoders, and that the one we're currently at should 512e1051a39Sopenharmony_ci * be tried. 513e1051a39Sopenharmony_ci * ok == 0 means that something failed in the recursion call 514e1051a39Sopenharmony_ci * above, making the result unsuitable for a chain. 515e1051a39Sopenharmony_ci * In this case, we simply continue to try finding a 516e1051a39Sopenharmony_ci * suitable encoder at this recursion level. 517e1051a39Sopenharmony_ci * ok == 1 means that the recursion call was successful, and we 518e1051a39Sopenharmony_ci * try to use the result at this recursion level. 519e1051a39Sopenharmony_ci */ 520e1051a39Sopenharmony_ci if (ok != 0) 521e1051a39Sopenharmony_ci break; 522e1051a39Sopenharmony_ci 523e1051a39Sopenharmony_ci OSSL_TRACE_BEGIN(ENCODER) { 524e1051a39Sopenharmony_ci BIO_printf(trc_out, 525e1051a39Sopenharmony_ci "[%d] Skipping because recusion level %d failed\n", 526e1051a39Sopenharmony_ci data->level, new_data.level); 527e1051a39Sopenharmony_ci } OSSL_TRACE_END(ENCODER); 528e1051a39Sopenharmony_ci } 529e1051a39Sopenharmony_ci 530e1051a39Sopenharmony_ci /* 531e1051a39Sopenharmony_ci * If |i < 0|, we didn't find any useful encoder in this recursion, so 532e1051a39Sopenharmony_ci * we do the rest of the process only if |i >= 0|. 533e1051a39Sopenharmony_ci */ 534e1051a39Sopenharmony_ci if (i < 0) { 535e1051a39Sopenharmony_ci ok = -1; 536e1051a39Sopenharmony_ci 537e1051a39Sopenharmony_ci OSSL_TRACE_BEGIN(ENCODER) { 538e1051a39Sopenharmony_ci BIO_printf(trc_out, 539e1051a39Sopenharmony_ci "[%d] (ctx %p) No suitable encoder found\n", 540e1051a39Sopenharmony_ci data->level, (void *)data->ctx); 541e1051a39Sopenharmony_ci } OSSL_TRACE_END(ENCODER); 542e1051a39Sopenharmony_ci } else { 543e1051a39Sopenharmony_ci /* Preparations */ 544e1051a39Sopenharmony_ci 545e1051a39Sopenharmony_ci switch (ok) { 546e1051a39Sopenharmony_ci case 0: 547e1051a39Sopenharmony_ci break; 548e1051a39Sopenharmony_ci case -1: 549e1051a39Sopenharmony_ci /* 550e1051a39Sopenharmony_ci * We have reached the beginning of the encoder instance sequence, 551e1051a39Sopenharmony_ci * so we prepare the object to be encoded. 552e1051a39Sopenharmony_ci */ 553e1051a39Sopenharmony_ci 554e1051a39Sopenharmony_ci /* 555e1051a39Sopenharmony_ci * |data->count_output_structure| is one of these values: 556e1051a39Sopenharmony_ci * 557e1051a39Sopenharmony_ci * -1 There is no desired output structure 558e1051a39Sopenharmony_ci * 0 There is a desired output structure, and it wasn't 559e1051a39Sopenharmony_ci * matched by any of the encoder instances that were 560e1051a39Sopenharmony_ci * considered 561e1051a39Sopenharmony_ci * >0 There is a desired output structure, and at least one 562e1051a39Sopenharmony_ci * of the encoder instances matched it 563e1051a39Sopenharmony_ci */ 564e1051a39Sopenharmony_ci if (data->count_output_structure == 0) 565e1051a39Sopenharmony_ci return 0; 566e1051a39Sopenharmony_ci 567e1051a39Sopenharmony_ci original_data = 568e1051a39Sopenharmony_ci data->ctx->construct(current_encoder_inst, 569e1051a39Sopenharmony_ci data->ctx->construct_data); 570e1051a39Sopenharmony_ci 571e1051a39Sopenharmony_ci /* Also set the data type, using the encoder implementation name */ 572e1051a39Sopenharmony_ci data->data_type = OSSL_ENCODER_get0_name(current_encoder); 573e1051a39Sopenharmony_ci 574e1051a39Sopenharmony_ci /* Assume that the constructor recorded an error */ 575e1051a39Sopenharmony_ci if (original_data != NULL) 576e1051a39Sopenharmony_ci ok = 1; 577e1051a39Sopenharmony_ci else 578e1051a39Sopenharmony_ci ok = 0; 579e1051a39Sopenharmony_ci break; 580e1051a39Sopenharmony_ci case 1: 581e1051a39Sopenharmony_ci if (!ossl_assert(data->running_output != NULL)) { 582e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR); 583e1051a39Sopenharmony_ci ok = 0; 584e1051a39Sopenharmony_ci break; 585e1051a39Sopenharmony_ci } 586e1051a39Sopenharmony_ci 587e1051a39Sopenharmony_ci { 588e1051a39Sopenharmony_ci /* 589e1051a39Sopenharmony_ci * Create an object abstraction from the latest output, which 590e1051a39Sopenharmony_ci * was stolen from the previous round. 591e1051a39Sopenharmony_ci */ 592e1051a39Sopenharmony_ci 593e1051a39Sopenharmony_ci OSSL_PARAM *abstract_p = abstract; 594e1051a39Sopenharmony_ci const char *prev_output_structure = 595e1051a39Sopenharmony_ci OSSL_ENCODER_INSTANCE_get_output_structure(data->prev_encoder_inst); 596e1051a39Sopenharmony_ci 597e1051a39Sopenharmony_ci *abstract_p++ = 598e1051a39Sopenharmony_ci OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, 599e1051a39Sopenharmony_ci (char *)data->data_type, 0); 600e1051a39Sopenharmony_ci if (prev_output_structure != NULL) 601e1051a39Sopenharmony_ci *abstract_p++ = 602e1051a39Sopenharmony_ci OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, 603e1051a39Sopenharmony_ci (char *)prev_output_structure, 604e1051a39Sopenharmony_ci 0); 605e1051a39Sopenharmony_ci *abstract_p++ = 606e1051a39Sopenharmony_ci OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, 607e1051a39Sopenharmony_ci data->running_output, 608e1051a39Sopenharmony_ci data->running_output_length); 609e1051a39Sopenharmony_ci *abstract_p = OSSL_PARAM_construct_end(); 610e1051a39Sopenharmony_ci current_abstract = abstract; 611e1051a39Sopenharmony_ci } 612e1051a39Sopenharmony_ci break; 613e1051a39Sopenharmony_ci } 614e1051a39Sopenharmony_ci 615e1051a39Sopenharmony_ci /* Calling the encoder implementation */ 616e1051a39Sopenharmony_ci 617e1051a39Sopenharmony_ci if (ok) { 618e1051a39Sopenharmony_ci OSSL_CORE_BIO *cbio = NULL; 619e1051a39Sopenharmony_ci BIO *current_out = NULL; 620e1051a39Sopenharmony_ci 621e1051a39Sopenharmony_ci /* 622e1051a39Sopenharmony_ci * If we're at the last encoder instance to use, we're setting up 623e1051a39Sopenharmony_ci * final output. Otherwise, set up an intermediary memory output. 624e1051a39Sopenharmony_ci */ 625e1051a39Sopenharmony_ci if (top) 626e1051a39Sopenharmony_ci current_out = data->bio; 627e1051a39Sopenharmony_ci else if ((current_out = allocated_out = BIO_new(BIO_s_mem())) 628e1051a39Sopenharmony_ci == NULL) 629e1051a39Sopenharmony_ci ok = 0; /* Assume BIO_new() recorded an error */ 630e1051a39Sopenharmony_ci 631e1051a39Sopenharmony_ci if (ok) 632e1051a39Sopenharmony_ci ok = (cbio = ossl_core_bio_new_from_bio(current_out)) != NULL; 633e1051a39Sopenharmony_ci if (ok) { 634e1051a39Sopenharmony_ci ok = current_encoder->encode(current_encoder_ctx, cbio, 635e1051a39Sopenharmony_ci original_data, current_abstract, 636e1051a39Sopenharmony_ci data->ctx->selection, 637e1051a39Sopenharmony_ci ossl_pw_passphrase_callback_enc, 638e1051a39Sopenharmony_ci &data->ctx->pwdata); 639e1051a39Sopenharmony_ci OSSL_TRACE_BEGIN(ENCODER) { 640e1051a39Sopenharmony_ci BIO_printf(trc_out, 641e1051a39Sopenharmony_ci "[%d] (ctx %p) Running encoder instance %p => %d\n", 642e1051a39Sopenharmony_ci data->level, (void *)data->ctx, 643e1051a39Sopenharmony_ci (void *)current_encoder_inst, ok); 644e1051a39Sopenharmony_ci } OSSL_TRACE_END(ENCODER); 645e1051a39Sopenharmony_ci } 646e1051a39Sopenharmony_ci 647e1051a39Sopenharmony_ci ossl_core_bio_free(cbio); 648e1051a39Sopenharmony_ci data->prev_encoder_inst = current_encoder_inst; 649e1051a39Sopenharmony_ci } 650e1051a39Sopenharmony_ci } 651e1051a39Sopenharmony_ci 652e1051a39Sopenharmony_ci /* Cleanup and collecting the result */ 653e1051a39Sopenharmony_ci 654e1051a39Sopenharmony_ci OPENSSL_free(data->running_output); 655e1051a39Sopenharmony_ci data->running_output = NULL; 656e1051a39Sopenharmony_ci 657e1051a39Sopenharmony_ci /* 658e1051a39Sopenharmony_ci * Steal the output from the BIO_s_mem, if we did allocate one. 659e1051a39Sopenharmony_ci * That'll be the data for an object abstraction in the next round. 660e1051a39Sopenharmony_ci */ 661e1051a39Sopenharmony_ci if (allocated_out != NULL) { 662e1051a39Sopenharmony_ci BUF_MEM *buf; 663e1051a39Sopenharmony_ci 664e1051a39Sopenharmony_ci BIO_get_mem_ptr(allocated_out, &buf); 665e1051a39Sopenharmony_ci data->running_output = (unsigned char *)buf->data; 666e1051a39Sopenharmony_ci data->running_output_length = buf->length; 667e1051a39Sopenharmony_ci memset(buf, 0, sizeof(*buf)); 668e1051a39Sopenharmony_ci } 669e1051a39Sopenharmony_ci 670e1051a39Sopenharmony_ci BIO_free(allocated_out); 671e1051a39Sopenharmony_ci if (original_data != NULL) 672e1051a39Sopenharmony_ci data->ctx->cleanup(data->ctx->construct_data); 673e1051a39Sopenharmony_ci return ok; 674e1051a39Sopenharmony_ci} 675