关于理解bio_push的openssl问题

时间:2016-09-15 11:44:44

标签: openssl

Hy i目前在c中编写一个程序,该程序应该从签名文件+公钥验证文件。

我从openssl二进制代码中复制了以下代码:

#include <BeTypes.h>
#include <mtypes.h>

#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/crypto.h>

typedef struct {
    char *signature;
    int len;
} Signature;

#define BUFFER_SIZE 1024*8

/**
 * @brief reads a public key from PEM File
 *
 * @return EVP_PKEY containing the public key.
 *         Return Value must be released with EVP_PKEY_free();
 */
static EVP_PKEY *getPubKeyFromPEM(const char *filename) {
    EVP_PKEY *pubkey = NULL;
    BIO *bio_publickey = BIO_new_file(filename, "r");
    pubkey = PEM_read_bio_PUBKEY(bio_publickey, NULL, NULL, NULL);
    BIO_free(bio_publickey);
    return pubkey;
}

/**
 * @brief Reads Signatuer File
 * @param filename_signature File path to signature file
 * @param signature_maxlen   Max Len for the Signature Buffer
 * @return Signature containing len and the signature data
 *         Return Value must be released with OPENSSL_free()
 */
static Signature *getSignature(const char *filename_signature, int signature_maxlen) {
    BIO *bio_signature = NULL;
    Signature *ret;

    //allocate return Object:
    ret = OPENSSL_malloc(sizeof(Signature));
    if(ret == NULL) {
        return NULL;
    }

    //init return Object:
    ret->signature = OPENSSL_malloc(signature_maxlen);
    bio_signature = BIO_new_file(filename_signature, "rb");
    ret->len = BIO_read(bio_signature, ret->signature, signature_maxlen);

    //Free Read
    BIO_free(bio_signature);

    return ret;
}

BOOL thrusted_checkFile(const char *filename_pubKey, const char *filename_signature, const char *filename_signedfile) {
    BOOL valid = FALSE;

    EVP_PKEY *pubkey = NULL;

    Signature *signature = NULL;

    EVP_MD_CTX *ctx_md = NULL;
    BIO *biomd;
    EVP_PKEY_CTX *pctx = NULL;
    BIO *input;
    BIO *in;
    EVP_MD_CTX *tctx;
    const EVP_MD *md;
    unsigned char *buf = NULL;
    EVP_MD_CTX *ctx;

    //Load Public key:
    pubkey = getPubKeyFromPEM(filename_pubKey);
    if(pubkey == NULL) {
        return FALSE;
    }

    signature = getSignature(filename_signature, EVP_PKEY_size(pubkey));

    //creates the thing whoever this thing is...
    biomd = BIO_new(BIO_f_md());
    if(biomd == NULL) {
        return FALSE;
    }

    //Create HashAlgorythm Context
    if(!BIO_get_md_ctx(biomd, &ctx_md)){
        return FALSE;
    }

    //Init pctx:
    if(!EVP_DigestVerifyInit(ctx_md, &pctx, NULL, NULL, pubkey)) {
        return FALSE;
    }

    in = BIO_new(BIO_s_file());
    if(in == NULL) {
        return FALSE;
    }

    input = BIO_push(biomd, in);

    BIO_get_md_ctx(biomd, &tctx);
    md = EVP_MD_CTX_md(tctx);

    if(BIO_read_filename(in, filename_signedfile) <= 0) {
        return FALSE;
    }

    buf = OPENSSL_malloc(BUFFER_SIZE);
    if(buf == NULL) {
        return FALSE;
    }

    while(TRUE) {
        int i = BIO_read(input, (char *)buf, BUFFER_SIZE);
        if(i < 0) {
            return FALSE;
        } else if(i == 0) {
            break;
        }
    }

    BIO_get_md_ctx(input, &ctx);
    valid = EVP_DigestVerifyFinal(ctx, signature->signature, signature->len) > 0;
    printf("No Error on check!\n");

    return valid;
}

我现在尝试理解这段代码并尝试简化它。

  1. 我对一个bio的理解就像一个流,它可以在java中有一些像map函数的东西,所以你给它一个输入,它使用一个由ctx和你输出的输出选择的函数转换后的价值观。

  2. 我不明白的是,BIO_push的作用是什么? 当我直接使用biomd时,我不明白这种差异。

1 个答案:

答案 0 :(得分:0)

实际上BIO不像是具有地图功能的流。 BIO是一个缓冲IO,用作OpenSSL库的输入或输出内存。

BIO_PUSH将第二个参数附加到第一个参数。这意味着在您的代码中“BIO in”附加到“BIO biomd”。

您可以在BIO_PUSH manpage中找到有关它的更多信息:

  

对于这些例子,假设md1和md2是摘要BIO,b64是a   base64 BIO和f是文件BIO。

     

如果致电:

     

BIO_push(b64,f);然后新链将成为b64链。后   拨打电话BIO_push(md2,b64); BIO_push(md1,md2);新的连锁店   是md1-md2-b64-f。写入md1的数据将被md1和md2消化,   base64编码并写入f。应该注意阅读   导致数据反向传递,即读取数据   从f,base64解码并被md1和md2消化。如果通话:

     

BIO_pop(MD2);该调用将返回b64,新链将返回   md1-b64-f数据可以像以前一样写入md1。