crypto/pkcs7/bio/md.c (145 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <errno.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include <openssl/pkcs7.h>
#include "../../internal.h"
#include "../crypto/bio/internal.h"
#include "../internal.h"
static int md_new(BIO *b) {
GUARD_PTR(b);
EVP_MD_CTX *ctx;
ctx = EVP_MD_CTX_new();
if (ctx == NULL) {
return 0;
}
BIO_set_data(b, ctx);
return 1;
}
static int md_free(BIO *b) {
GUARD_PTR(b);
EVP_MD_CTX_free(BIO_get_data(b));
BIO_set_data(b, NULL);
BIO_set_init(b, 0);
return 1;
}
static int md_read(BIO *b, char *out, int outl) {
GUARD_PTR(b);
GUARD_PTR(out);
int ret = 0;
EVP_MD_CTX *ctx;
BIO *next;
ctx = BIO_get_data(b);
next = BIO_next(b);
if ((ctx == NULL) || (next == NULL) || outl <= 0) {
return 0;
}
ret = BIO_read(next, out, outl);
if (ret > 0) {
if (EVP_DigestUpdate(ctx, (unsigned char *)out, ret) <= 0) {
ret = -1;
}
}
BIO_clear_retry_flags(b);
BIO_copy_next_retry(b);
return ret;
}
static int md_write(BIO *b, const char *in, int inl) {
GUARD_PTR(b);
GUARD_PTR(in);
int ret = 0;
EVP_MD_CTX *ctx;
BIO *next;
ctx = BIO_get_data(b);
next = BIO_next(b);
if ((ctx == NULL) || (next == NULL) || inl <= 0) {
return 0;
}
ret = BIO_write(next, in, inl);
if (ret > 0) {
if (EVP_DigestUpdate(ctx, (const unsigned char *)in, ret) <= 0) {
ret = -1;
}
}
BIO_clear_retry_flags(b);
BIO_copy_next_retry(b);
return ret;
}
static long md_ctrl(BIO *b, int cmd, long num, void *ptr) {
GUARD_PTR(b);
EVP_MD_CTX *ctx, **pctx;
EVP_MD *md;
long ret = 1;
BIO *next;
ctx = BIO_get_data(b);
next = BIO_next(b);
switch (cmd) {
case BIO_CTRL_RESET:
if (BIO_get_init(b)) {
ret = EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL);
} else {
ret = 0;
}
if (ret > 0) {
ret = BIO_ctrl(next, cmd, num, ptr);
}
break;
case BIO_C_GET_MD_CTX:
pctx = ptr;
*pctx = ctx;
BIO_set_init(b, 1);
break;
case BIO_C_SET_MD:
GUARD_PTR(ptr);
md = ptr;
ret = EVP_DigestInit_ex(ctx, md, NULL);
if (ret > 0) {
BIO_set_init(b, 1);
}
break;
// OpenSSL implements these, but because we don't need them and cipher BIO
// is internal, we can fail loudly if they're called. If this case is hit,
// it likely means you're making a change that will require implementing
// these.
case BIO_C_GET_MD:
case BIO_C_SET_MD_CTX:
case BIO_C_DO_STATE_MACHINE:
case BIO_CTRL_DUP:
case BIO_CTRL_GET_CALLBACK:
case BIO_CTRL_SET_CALLBACK:
OPENSSL_PUT_ERROR(PKCS7, ERR_R_BIO_LIB);
return 0;
default:
ret = BIO_ctrl(next, cmd, num, ptr);
break;
}
return ret;
}
static int md_gets(BIO *b, char *buf, int size) {
GUARD_PTR(b);
GUARD_PTR(buf);
EVP_MD_CTX *ctx;
unsigned int ret;
ctx = BIO_get_data(b);
if (((size_t)size) < EVP_MD_CTX_size(ctx)) {
return 0;
}
if (EVP_DigestFinal_ex(ctx, (unsigned char *)buf, &ret) <= 0) {
return -1;
}
return ret;
}
static const BIO_METHOD methods_md = {
BIO_TYPE_MD, // type
"message digest", // name
md_write, // bwrite
md_read, // bread
NULL, // bputs
md_gets, // bgets
md_ctrl, // ctrl
md_new, // create
md_free, // destroy
NULL, // callback_ctrl
};
const BIO_METHOD *BIO_f_md(void) { return &methods_md; }
int BIO_get_md_ctx(BIO *b, EVP_MD_CTX **ctx) {
return BIO_ctrl(b, BIO_C_GET_MD_CTX, 0, ctx);
}
int BIO_set_md(BIO *b, const EVP_MD *md) {
return BIO_ctrl(b, BIO_C_SET_MD, 0, (EVP_MD*)md);
}