如何使用ECDSA以编程方式创建自签名数字证书

时间:2016-03-09 18:41:56

标签: openssl digital-signature pki ecdsa

我正在尝试创建一个数字证书,该证书可以使用EC密钥进行自签名,而不是来自RSA的数据证书,并遵循这些SO link1link2。我将签名算法从link1中给出的RSA替换为EC

EC_KEY *ecc = NULL;
int eccgrp = OBJ_txt2nid("secp256k1");
ecc = EC_KEY_new_by_curve_name(eccgrp);
EC_KEY_set_asn1_flag(ecc, OPENSSL_EC_NAMED_CURVE);

if(!(EC_KEY_generate_key(ecc))) {
    BIO_printf(out, "Error in generating key");
    printf("Error 1\n");
}

if(!EVP_PKEY_assign_EC_KEY(pk, ecc)) {
    BIO_printf(out, "Error assigning EC_KEY to EVP_PKEY");
    printf("Error 2\n");
}
.
.
X509_set_pubkey(x,pk);
.
.
if (!X509_sign(x,pk,EVP_md5()))
    goto err;
.
.

其余代码与link1中给出的相同。没有打印错误,但是当我尝试打印x509证书X509_print_fp(stdout,x509);时,我遇到了段错误。这样做的正确方法是什么?

1 个答案:

答案 0 :(得分:2)

您更改that code比您说的更多,因为它没有变量&p?pk'或者' x'。

无论何时从libcrypto例程中获得错误/失败返回,您都应该始终查看错误队列;见https://www.openssl.org/docs/faq.html#PROG6https://www.openssl.org/docs/faq.html#PROG7。 (对于libssl例程,您应该根据SSL_get_error的返回值执行此操作。)如果您按照下面的代码执行此操作,那么“错误”将会执行此操作。如果您看到X509_sign失败

140018941793960:error:100C508A:elliptic curve routines:PKEY_EC_CTRL:invalid digest type:ec_pmeth.c:388:

因为标准的ECDSA签名方案不包括MD5。 您必须使用SHA1或SHA2 ,并且使用与ECC密钥匹配的哈希密钥,在本例中为ECC256。由于签名失败,x509结构不包含有效数据,因此无法成功打印。

另请注意:自1.0.0(2010年)PEM_write_PrivateKey enc非空用后使用' new' (约2000年!)PKCS#8 / PBES2格式,需要OpenSSL_add_all_algorithms的合适变体。

完整的工作演示质量代码:

/* SO #35899969 */
#include <stdio.h>
#include <stdlib.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#ifdef _WIN32
#include <openssl/applink.c>
#endif

/* minimal error handling for demo; real code do better */
void err (const char *label)
{
  fprintf (stderr, "Error in %s:\n", label);
  ERR_print_errors_fp (stderr);
  exit (1);
}

int main (int argc, char**argv)
{
  int bad = argc>1;
  ERR_load_crypto_strings(); /* or SSL_load_error_strings */
  OPENSSL_add_all_algorithms_noconf(); /* for PKCS8 w PBES2 */

  EVP_PKEY * pkey = EVP_PKEY_new();
  EC_KEY *ecc = EC_KEY_new_by_curve_name(NID_secp256k1);
  /* simpler than going through OBJ_txt2nid */
  if(!ecc) err("ECCnewbyname");
  EC_KEY_set_asn1_flag(ecc, OPENSSL_EC_NAMED_CURVE);
  if(!(EC_KEY_generate_key(ecc))) err("ECCgen");
  if(!EVP_PKEY_assign_EC_KEY(pkey, ecc)) err("PKEYassign");

  X509 * x509 = X509_new();
  /* REALLY shouldn't use fixed serial if DN isn't unique */
  ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
  X509_gmtime_adj(X509_get_notBefore(x509), 0);
  X509_gmtime_adj(X509_get_notAfter(x509), 365L*86400);
  X509_set_pubkey(x509, pkey);
  X509_NAME * name = X509_get_subject_name(x509);
  X509_NAME_add_entry_by_txt(name, "C",  MBSTRING_ASC,
                           (unsigned char *)"CA", -1, -1, 0);
  X509_NAME_add_entry_by_txt(name, "O",  MBSTRING_ASC,
                           (unsigned char *)"MyCompany Inc.", -1, -1, 0);
  X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
                           (unsigned char *)"localhost", -1, -1, 0);
  X509_set_issuer_name(x509, name);
  if(!X509_sign(x509, pkey, bad? EVP_md5(): EVP_sha256())) err("X509sign");

  /* simplified */
  if(!PEM_write_PrivateKey(stdout, pkey, EVP_des_ede3_cbc(),
                          NULL,0,NULL,"passphrase")) 
    err("writeKey");
  if(!PEM_write_X509(stdout, x509))
    err("writeCert");
  /* added */
  X509_print_fp (stdout, x509); 
  return 0;
}