首页 文章

使用OpenSSL以编程方式创建X509证书

提问于
浏览
64

我有一个C / C应用程序,我需要创建一个包含公钥和私钥的X509 pem证书 . 证书可以是自签名的,也可以是未签名的,无关紧要 .

我想在应用程序中执行此操作,而不是从命令行执行此操作 .

什么OpenSSL功能会为我做这个?任何示例代码都是奖金!

4 回答

  • 42

    您首先需要熟悉术语和机制 .

    根据定义,X.509 certificate 不包含私钥 . 相反,它是公钥的CA签名版本(以及CA放入签名的任何属性) . PEM格式实际上只支持密钥和证书的单独存储 - 尽管您可以将两者连接起来 .

    在任何情况下,您都需要调用OpenSSL API的20个不同功能来创建密钥和自签名证书 . 一个例子是OpenSSL源本身,在demos/x509/mkcert.c

    有关更详细的答案,请参阅下面的Nathan Osman's explanation .

  • 162

    我意识到这是一个非常晚(和很长)的答案 . 但考虑到这个问题在搜索引擎结果中的排名有多好,我认为可能值得写一个体面的答案 .

    您将在下面阅读的很多内容都来自this demo和OpenSSL文档 . 以下代码适用于C和C.


    在我们实际创建证书之前,我们需要创建一个私钥 . OpenSSL提供 EVP_PKEY 结构,用于在内存中存储与算法无关的私钥 . 此结构在 openssl/evp.h 中声明,但由 openssl/x509.h (稍后我们将需要)包含,因此您不需要明确包含标头 .

    为了分配 EVP_PKEY 结构,我们使用EVP_PKEY_new

    EVP_PKEY * pkey;
    pkey = EVP_PKEY_new();
    

    还有一个用于释放结构的相应函数 - EVP_PKEY_free - 它接受一个参数:上面初始化的 EVP_PKEY 结构 .

    现在我们需要生成一个密钥 . 对于我们的示例,我们将生成RSA密钥 . 这是通过在 openssl/rsa.h 中声明的RSA_generate_key函数完成的 . 此函数返回指向 RSA 结构的指针 .

    对函数的简单调用可能如下所示:

    RSA * rsa;
    rsa = RSA_generate_key(
        2048,   /* number of bits for the key - 2048 is a sensible value */
        RSA_F4, /* exponent - RSA_F4 is defined as 0x10001L */
        NULL,   /* callback - can be NULL if we aren't displaying progress */
        NULL    /* callback argument - not needed in this case */
    );
    

    如果 RSA_generate_key 的返回值是 NULL ,那么出错了 . 如果没有,那么我们现在有一个RSA密钥,我们可以从之前将它分配给我们的 EVP_PKEY 结构:

    EVP_PKEY_assign_RSA(pkey, rsa);
    

    释放 EVP_PKEY 结构时,将自动释放 RSA 结构 .


    现在为证书本身 .

    OpenSSL使用 X509 结构在内存中表示x509证书 . 此结构的定义位于 openssl/x509.h 中 . 我们需要的第一个功能是X509_new . 它的用途相对简单:

    X509 * x509;
    x509 = X509_new();
    

    EVP_PKEY 的情况一样,有一个相应的函数可以释放结构 - X509_free .

    现在我们需要使用一些 X509_* 函数设置证书的一些属性:

    ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
    

    这会将证书的序列号设置为“1” . 某些开源HTTP服务器拒绝接受序列号为“0”的证书,这是默认值 . 下一步是指定证书实际有效的时间 Span . 我们通过以下两个函数调用来实现:

    X509_gmtime_adj(X509_get_notBefore(x509), 0);
    X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);
    

    第一行将证书的 notBefore 属性设置为当前时间 . ( X509_gmtime_adj 函数将指定的秒数添加到当前时间 - 在本例中为none . )第二行将证书的 notAfter 属性设置为从现在起365天(60秒* 60分钟* 24小时* 365天) .

    现在我们需要使用之前生成的密钥为我们的证书设置公钥:

    X509_set_pubkey(x509, pkey);
    

    由于这是一个自签名证书,我们将发行者的名称设置为主题的名称 . 该过程的第一步是获取主题名称:

    X509_NAME * name;
    name = X509_get_subject_name(x509);
    

    如果您之前在命令行上创建过自签名证书,则可能记得被要求提供国家/地区代码 . 这是我们提供它以及组织('O')和通用名称('CN')的地方:

    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);
    

    (我'm using the value ' CA ' here because I' m加拿大人,那是我们的国家代码 . 另请注意,参数#4需要明确地转换为 unsigned char * . )

    现在我们可以实际设置发行者名称:

    X509_set_issuer_name(x509, name);
    

    最后,我们准备好执行签名过程 . 我们用之前生成的密钥调用 X509_sign . 这个代码很简单:

    X509_sign(x509, pkey, EVP_sha1());
    

    请注意,我们使用SHA-1哈希算法对密钥进行签名 . 这与我在本答案开头提到的使用MD5的 mkcert.c 演示不同 .


    我们现在有一个自签名证书!但我们尚未完成 - 我们需要将这些文件写入磁盘 . 值得庆幸的是OpenSSL也在那里覆盖了 PEM_* 函数,这些函数在 openssl/pem.h 中声明 . 我们需要的第一个是 PEM_write_PrivateKey 用于保存我们的私钥 .

    FILE * f;
    f = fopen("key.pem", "wb");
    PEM_write_PrivateKey(
        f,                  /* write the key to the file we've opened */
        pkey,               /* our key from earlier */
        EVP_des_ede3_cbc(), /* default cipher for encrypting the key on disk */
        "replace_me",       /* passphrase required for decrypting the key on disk */
        10,                 /* length of the passphrase string */
        NULL,               /* callback for requesting a password */
        NULL                /* data to pass to the callback */
    );
    

    如果您不想加密私钥,则只需传递 NULL 作为上面的第三个和第四个参数 . 无论哪种方式,您肯定希望确保该文件不是世界可读的 . (对于Unix用户,这意味着 chmod 600 key.pem . )

    呼!现在我们归结为一个函数 - 我们需要将证书写入磁盘 . 我们需要的功能是 PEM_write_X509

    FILE * f;
    f = fopen("cert.pem", "wb");
    PEM_write_X509(
        f,   /* write the certificate to the file we've opened */
        x509 /* our certificate */
    );
    

    我们完成了!希望这个答案中的信息足以让你大致了解一切是如何工作的,尽管我们几乎没有触及OpenSSL的表面 .

    对于那些有兴趣看到上面的所有代码在真实应用程序中看起来像什么的人,我把一个Gist(用C语言编写)放在一起,你可以查看here .

  • 2

    有没有机会通过你的应用程序内的 system 电话这样做?这样做的几个很好的理由:

    • 许可:调用 openssl 可执行文件可以将它与您的应用程序分开,并可能提供某些优势 . 免责声明:就此问题咨询律师 .

    • 文档:OpenSSL带有非凡的命令行文档,极大地简化了可能复杂的工具 .

    • 可测试性:您可以从命令行执行OpenSSL,直到您完全了解如何创建证书 . 有很多选择;期待花一天时间,直到你得到所有细节 . 在那之后,将命令合并到您的应用程序中是微不足道的 .

    如果您选择使用API,请查看www.openssl.org上的 openssl-dev 开发人员列表 .

    祝好运!

  • 0

    创建数字证书的非常简单的教程http://publib.boulder.ibm.com/infocenter/rsthelp/v8r0m0/index.jsp?topic=/com.ibm.rational.test.lt.doc/topics/tcreatecertopenssl.html

    关于从代码执行这些命令我不确定 .

相关问题