int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) { unsigned char *tmp_buf; if ((in == NULL) || (in->digest == NULL)) { EVPerr(EVP_F_EVP_MD_CTX_COPY_EX,EVP_R_INPUT_NOT_INITIALIZED); return 0; } #ifndef OPENSSL_NO_ENGINE /* Make sure it's safe to copy a digest context using an ENGINE */ if (in->engine && !ENGINE_init(in->engine)) { EVPerr(EVP_F_EVP_MD_CTX_COPY_EX,ERR_R_ENGINE_LIB); return 0; } #endif if (out->digest == in->digest) { tmp_buf = out->md_data; EVP_MD_CTX_set_flags(out,EVP_MD_CTX_FLAG_REUSE); } else tmp_buf = NULL; EVP_MD_CTX_cleanup(out); memcpy(out,in,sizeof *out); if (in->md_data && out->digest->ctx_size) { if (tmp_buf) out->md_data = tmp_buf; else { out->md_data=OPENSSL_malloc(out->digest->ctx_size); if (!out->md_data) { EVPerr(EVP_F_EVP_MD_CTX_COPY_EX,ERR_R_MALLOC_FAILURE); return 0; } } memcpy(out->md_data,in->md_data,out->digest->ctx_size); } out->update = in->update; if (in->pctx) { out->pctx = EVP_PKEY_CTX_dup(in->pctx); if (!out->pctx) { EVP_MD_CTX_cleanup(out); return 0; } } if (out->digest->copy) return out->digest->copy(out,in); return 1; }
int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen) { int sctx = 0, r = 0; EVP_PKEY_CTX *pctx = ctx->pctx; if (pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) { if (!sigret) return pctx->pmeth->signctx(pctx, sigret, siglen, ctx); if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) r = pctx->pmeth->signctx(pctx, sigret, siglen, ctx); else { EVP_PKEY_CTX *dctx = EVP_PKEY_CTX_dup(ctx->pctx); if (!dctx) return 0; r = dctx->pmeth->signctx(dctx, sigret, siglen, ctx); EVP_PKEY_CTX_free(dctx); } return r; } if (pctx->pmeth->signctx) sctx = 1; else sctx = 0; if (sigret) { unsigned char md[EVP_MAX_MD_SIZE]; unsigned int mdlen = 0; if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) { if (sctx) r = ctx->pctx->pmeth->signctx(ctx->pctx, sigret, siglen, ctx); else r = EVP_DigestFinal_ex(ctx, md, &mdlen); } else { EVP_MD_CTX tmp_ctx; EVP_MD_CTX_init(&tmp_ctx); if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) return 0; if (sctx) r = tmp_ctx.pctx->pmeth->signctx(tmp_ctx.pctx, sigret, siglen, &tmp_ctx); else r = EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen); EVP_MD_CTX_cleanup(&tmp_ctx); } if (sctx || !r) return r; if (EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen) <= 0) return 0; } else { if (sctx) { if (pctx->pmeth->signctx(pctx, sigret, siglen, ctx) <= 0) return 0; } else { int s = EVP_MD_size(ctx->digest); if (s < 0 || EVP_PKEY_sign(pctx, sigret, siglen, NULL, s) <= 0) return 0; } } return 1; }