2015-11-28 29 views
1

我正在构建一个实现ECDSA_METHOD的OpenSSL引擎,该引擎包含签名创建和签名验证功能。由于ECDHE私钥的唯一用法与创建签名有关,因此不需要从引擎导出密钥并将其呈现在其他任何位置。如何在没有可导出私钥的情况下执行ECDHE握手

但是,如果我不通过SSL_set_private_key功能SSL握手供应私钥SSL_Context失败,以下错误:

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密钥,但是我没有在任何地方找到它。任何其他解决方案也赞赏。

回答

1

任何其他解决方案,以及赞赏。

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

我以前做过这件事,而且遇到的唯一一件大事(除缺乏文档和示例外)在EVP级别缺少密钥存储功能。似乎有一些工作正在进行中,您可以看到here。作为一种解决方法,我必须从商店中选择密钥/证书作为密钥生成机制的一部分,但它并不是真正用于此目的的。

如果你决定走这条路,那么准备好几个星期的反复试验。

+0

它看起来像一个合理的解决方案,但它需要一个重要的“课程改变”。在尝试你的建议之前,我将探讨另一个简单的想法 - EC_KEY由两部分组成 - 32位私钥和64位公钥(对于256位曲线),所以如果我创建一个模拟“私钥”从证书和非零模拟私钥获取的有效公钥,然后我可能会绕过我的第二种方法中提到的openssl验证规则。我会让你知道结果。 –

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; 
} 
相关问题