1

我正在构建一个实现 ECDSA_METHOD 的 OpenSSL 引擎,其中包括签名创建和签名验证功能。由于 ECDHE 私钥的唯一用途与签名创建有关,因此不需要从引擎中导出密钥并将其显示在其他任何地方。

但是,如果我不通过 SSL_set_private_key 函数向 SSL_Context 提供私钥,则 SSL 握手失败并出现以下错误:

error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

我还尝试向 SSL_set_private_key 函数提供一个模拟密钥(与证书中的公钥无关的密钥),但此函数确实验证私钥/公钥是否匹配,如果它们不匹配,则会引发关于错误证书的错误吨。

看起来 openssl 在某些情况下允许绕过此验证,例如,这是我在 ssl/ssl_rsa.c 中找到的

#ifndef OPENSSL_NO_RSA
    /*
     * Don't check the public/private key, this is mostly for smart
     * cards.
     */
    if ((pkey->type == EVP_PKEY_RSA) &&
        (RSA_flags(pkey->pkey.rsa) & RSA_METHOD_FLAG_NO_CHECK)) ;
    else
#endif
    if (!X509_check_private_key(c->pkeys[i].x509, pkey)) {
        X509_free(c->pkeys[i].x509);
        c->pkeys[i].x509 = NULL;
        return 0;
    }

我想,我需要一个类似的 EC 密钥,但我在任何地方都找不到。任何其他解决方案也值得赞赏。

4

2 回答 2

1

任何其他解决方案也值得赞赏。

这可能不是您拥有的唯一选择,但我认为您可以通过创建自己的EVP_PKEY_METHOD并根据需要实现其功能来实现您正在寻找的东西。这样,您可以存储自己的句柄,例如基于智能卡的密钥,然后在适当的时候调用正确的签名方法。您必须使用EVP_PKEY_meth_set_Xyz()函数设置正确的方法,例如EVP_PKEY_meth_set_sign(<yourSigningFunction>). 例如,如果您使用的是 Windows 加密 API,则必须NCryptSignHash()从您的签名函数中调用。这样,您不必从 Windows 密钥库中导出私钥来获取签名。

我以前做过这个,我遇到的唯一一件大事(除了缺乏文档和示例)是缺少关键存储功能EVP。如您所见,似乎有一些工作正在进行。作为一种解决方法,我必须从存储中选择密钥/证书作为密钥生成机制的一部分,而这并不是真正的目的。

如果您决定走这条路,请准备好几周的反复试验。

于 2015-12-06T17:01:05.893 回答
0

以下是如何通过提供一个 EC_KEY 的公钥集等于公共证书的公钥和私钥设置为任何非零值来绕过 openssl 验证规则(在我的示例中,我刚刚将其设置为公钥的 X 坐标)。创建密钥并将其存储在文件中后,可以将其作为常规私钥传递给 SSL_Context。

我认为,理想情况下,openssl 应该以更系统和更透明的方式解决这个问题,但在完成之前,建议的解决方案可以用作解决方法:

#include <string.h>
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>


static char * my_prog = "dummykey";
static char * key_file = NULL;
static char * cert_file = NULL;
int verbose = 0;

static void print_help() {

    fprintf(stderr,"Version: %s\nUSAGE: %s -cert in_cert_file -key out_key_file\n",
             VERSION, my_prog);
}

static void parse_args(int argc, char** argv) {

    argc--;
    argv++;

    while (argc >= 1) {
        if (!strcmp(*argv,"-key")) {
            key_file = *++argv;
            argc--;
        }
        else if (!strcmp(*argv,"-cert")) {
            cert_file = *++argv;
            argc--;
        }
        else if (!strcmp(*argv,"-v")) {
            verbose = 1;
        }
        else {
            fprintf(stderr, "%s: Invalid param: %s\n", my_prog, *argv);
            print_help();
            exit(1);
        }
        argc--;
        argv++;
    }

    if (key_file == NULL || cert_file == NULL ) {
        print_help();
        exit(1);
    }
}

int get_curve_nid(X509 *c) {
    int ret = 0;

    if (c->cert_info->key->algor->parameter) {
        ASN1_TYPE *p = c->cert_info->key->algor->parameter;
        if (p && p->type == V_ASN1_OBJECT) {
            ret = OBJ_obj2nid(c->cert_info->key->algor->parameter->value.object);
        }
    }
    return ret;
}

int main(int argc, char** argv) {
    X509 *c=NULL;
    FILE *fp=NULL;
    FILE *ofp=NULL;
    EC_POINT *ec_point = NULL;
    BIGNUM *x = NULL;
    BIGNUM *y = NULL;
    EC_KEY *ec_key = NULL;
    EC_GROUP *grp = NULL;

    parse_args(argc, argv);

    fp = fopen(cert_file, "r");
    if (!fp) {
        fprintf(stderr,"%s: Can't open %s\n", my_prog, cert_file);
        return 1;
    }
    c = PEM_read_X509 (fp, NULL, (int (*) ()) 0, (void *) 0);
    if (c) {
        x = BN_new();
        y = BN_new();
        int len = c->cert_info->key->public_key->length-1;
        BN_bin2bn(c->cert_info->key->public_key->data+1, len/2, x);
        BN_bin2bn(c->cert_info->key->public_key->data+1+len/2, len/2, y);

        EC_GROUP *grp = EC_GROUP_new_by_curve_name(get_curve_nid(c));

        ec_key = EC_KEY_new();
        int sgrp = EC_KEY_set_group(ec_key, grp);
        int sprk = EC_KEY_set_private_key(ec_key, x);
        if (sgrp && sprk) {
           ec_point = EC_POINT_new(grp);
            int ac = EC_POINT_set_affine_coordinates_GFp(grp, ec_point, x, y, BN_CTX_new());
            int spub =EC_KEY_set_public_key(ec_key, ec_point);

            ofp = fopen(key_file, "w");
            int r = 0;
            if (ofp) {
                r = PEM_write_ECPrivateKey(ofp, ec_key, NULL, NULL, 0, NULL, NULL);
                if (!r)
                        fprintf(stderr,"%s: Can't write EC key %p to %s\n", my_prog, ec_key, key_file);
            }
            else {
                        fprintf(stderr,"%s: Can't open %s\n", my_prog, key_file);
            }
        }
    }
    if (ec_key)
        EC_KEY_free(ec_key);
    if (grp)
        EC_GROUP_free(grp);
    if (x)
        BN_free(x);
    if (y)
        BN_free(y);
    if (c)
        X509_free (c);
    if (fp)
        fclose(fp);
    if (ofp)
        fclose(ofp);
    return 0;
}
于 2015-12-07T21:39:41.573 回答