在 C 中使用 openssl 生成 pem

Generating a pem with openssl in C

我正在开发一个关键的实用程序库,不幸的是,我在可靠地创建 pem 时遇到了一些困难。我成功地创建了一个 pem,可能有 98% 的时间,但时不时地我会得到一个坏的 pem。知道发生了什么事吗?

我正在编译 gcc key_utils.c tests.c -o key_tests -lcrypto -lssl -Wall

Headers:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
#include <openssl/ecdsa.h>
#include <openssl/pem.h>

.

int generatePem(char **pem) {

    char *pemholder = calloc(224, sizeof(char));
    EC_KEY *eckey = NULL;

    BIO *out = BIO_new(BIO_s_mem());
    BUF_MEM *buf = NULL;
    EC_GROUP *group = NULL;

    group = EC_GROUP_new_by_curve_name(NID_secp256k1);
    buf = BUF_MEM_new();
    eckey = EC_KEY_new();

    createNewKey(group, eckey);

    EC_GROUP_clear_free(group);

    PEM_write_bio_ECPrivateKey(out, eckey, NULL, NULL, 0, NULL, NULL);

    BIO_get_mem_ptr(out, &buf);

    memcpy(pemholder, buf->data, 223);

    if ( buf->data[219] == '\n') {
        pemholder[220] = '[=11=]';       
        memcpy(*pem, pemholder, 221);
    } else if ( buf->data[221] == '\n') {
        pemholder[222] = '[=11=]';       
        memcpy(*pem, pemholder, 223);
    } else {
        pemholder[223] = '[=11=]';
        memcpy(*pem, pemholder, 224);
    }

    free(pemholder);
    EC_KEY_free(eckey);
    BIO_free_all(out);

    return NOERROR;
};

坏的 pem 看起来像这样:

-----BEGIN EC PRIVATE KEY-----
MHMCAQEEH8kO/hjEyM2hvQk//LSsp1xRBIYNDRjAi4b8N78odyCgBwYFK4EEAAqh
RANCAAQ43017I40ci8YMLJnguD/DHUjohY4blKoJ4lXYbgYqyjWvJfVnsNPMU8H9
o3IdPwAitnJjCOG11n9DIQoS3S/o
-----END EC PRIVATE KEY-----
6T

原来我很笨,220 字节是一个有效的 PEM。

这是工作代码,以备日后其他人需要查看。

int generatePem(char **pem) {
    int returnError = NOERROR;
    char * errorMessage = "";
    char *pemholder = calloc(240, sizeof(char));
    EC_KEY *eckey = NULL;
    BIO *out = NULL;

    if ((out = BIO_new(BIO_s_mem())) == NULL) {
        returnError = ERROR;
        errorMessage = "Error in BIO_new(BIO_s_mem())";
        goto clearVariables;
    }

    BUF_MEM *buf = NULL;
    EC_GROUP *group = NULL;

    if ((group = EC_GROUP_new_by_curve_name(NID_secp256k1)) == NULL) {
        returnError = ERROR;
        errorMessage = "Error in EC_GROUP_new_by_curve_name(NID_secp256k1))";
        goto clearVariables;
    }

    if (((eckey = EC_KEY_new()) == NULL) ||
        ((buf = BUF_MEM_new()) == NULL)) {
        returnError = ERROR;
        errorMessage = "Error in EC_KEY_new())";
        goto clearVariables;
    };

    if (createNewKey(group, eckey) == ERROR) {
        returnError = ERROR;
        errorMessage = "createNewKey(group, eckey)";
        goto clearVariables;
    }

    if (PEM_write_bio_ECPrivateKey(out, eckey, NULL, NULL, 0, NULL, NULL) == 0) {
        printf("PEM_write_bio_ECPrivateKey error");
    }

    BIO_get_mem_ptr(out, &buf);

    memcpy(pemholder, buf->data, 224);
    if (buf->data[218] == '\n') {
        pemholder[219] = '[=10=]';
        memcpy(*pem, pemholder, 220);
    } else if ( buf->data[219] == '\n') {
        pemholder[220] = '[=10=]';       
        memcpy(*pem, pemholder, 221);
    } else if ( buf->data[221] == '\n') {
        pemholder[222] = '[=10=]';       
        memcpy(*pem, pemholder, 223);
    } else if (buf->data[222] == '\n') {
        pemholder[223] = '[=10=]';
        memcpy(*pem, pemholder, 224);
    } else {
        returnError = ERROR;
        errorMessage = "invalid PEM generated";
        goto clearVariables;
    }

    goto clearVariables;

clearVariables:
    if (group != NULL)
        EC_GROUP_clear_free(group);
    if (pemholder != NULL) 
        free(pemholder);
    if (eckey != NULL)
        EC_KEY_free(eckey);
    if (out != NULL)
        BIO_free_all(out);
    if (errorMessage[0] != '[=10=]')
        printf("Error: %s\n", errorMessage);

    return returnError;
};

static int createNewKey(EC_GROUP *group, EC_KEY *eckey) {

    int asn1Flag = OPENSSL_EC_NAMED_CURVE;
    int form = POINT_CONVERSION_UNCOMPRESSED;

    EC_GROUP_set_asn1_flag(group, asn1Flag);
    EC_GROUP_set_point_conversion_form(group, form);
    int setGroupError = EC_KEY_set_group(eckey, group);

    int resultFromKeyGen = EC_KEY_generate_key(eckey);

    if (resultFromKeyGen != 1 || setGroupError != 1){
        return ERROR;
    }

    return NOERROR;
}