【问题标题】:Export a PKCS#12 file without an export password?导出没有导出密码的 PKCS#12 文件?
【发布时间】:2015-02-14 08:33:15
【问题描述】:

我正在生成导出一些 pkcs#12 文件以用于测试目的。这些文件未在生产中使用,仅在自动化测试期间临时存在。

我正在使用以下命令:

openssl pkcs12 -export -nodes -out bundle.pfx -inkey mykey.key -in certificate.crt -certfile ca-cert.crt

为什么我加了-nodes后还要输入导出密码?

在 Ubuntu Server 14.10 64 位上,我的 OpenSSL 版本是 OpenSSL 1.0.1f 6 Jan 2014

【问题讨论】:

    标签: openssl command pkcs#12


    【解决方案1】:

    交互模式下,当提示输入密码时,直接回车,不会设置密码。

    如果您想自动执行该操作(例如作为 ansible 命令),请使用 -passout 参数。它期望参数的格式为pass:mypassword。因为我们不需要密码:

    openssl pkcs12 -export -nodes -out bundle.pfx -inkey mykey.key \
        -in certificate.crt -certfile ca-cert.crt \
        -passout pass:
    

    【讨论】:

    • 这会生成一个以空字符串为密码的文件,与没有密码不一样。您仍然必须在密码提示符下按 enter,这在 iOS 设备上不起作用,因为它们不允许您使用空字符串按 enter。
    • 我发现这在 CRON 进程中也不起作用。相反,我只是制作了一个临时密码并将其作为变量存储在脚本中,因为脚本的目的只是将 P12 格式的 Let's Encrypt 证书传输到 389-DS 实例。 (P12 文件之后立即被丢弃。)
    • -nodes 在使用 -export 时甚至不是有效参数,请参见手册页。按两次返回设置一个空密码,这与没有密码不同。 -passout pass: 也设置了一个空密码。我的回答通过查看代码证明,只有在直接使用 libcrypto 时,才能在命令行上创建没有密码的 PKCS#12 文件。 @Nick 是绝对正确的。
    • @Nick my openssl 在我将 PEM 通行证留空时抛出错误,为什么?
    • 请参阅answer further down,了解如何通过 openssl 而不是空字符串密码创建具有 NO 密码的 pcks12。
    【解决方案2】:

    tl;dr 如果您将加密算法都明确设置为NONE(用于密钥的算法和用于证书的算法),您仍然需要提供密码,但没有执行加密时,您提供的密码无关紧要,因为密码会被忽略并且生成的文件未加密。

    如需完整的命令行示例,请查看此回复:
    https://stackoverflow.com/a/62863490/7878845

    很详细的回答:

    -nodes 表示“不加密私钥”,但在 PKCS#12 文件中,证书也是加密的,因此即使使用 -nodes,您也需要导出密码。

    查看-descert 的文档:

    使用三重 DES 加密证书;这可能会呈现 PKCS#12 文件 某些“出口级”软件无法读取。默认情况下,私钥是 使用三重 DES 加密,证书使用 40 位 RC2。

    因此,除非您使用此选项,否则证书将使用 RC2 加密。您可以使用选项-keypbe-certpbe 更改密钥或证书的算法。

    同样对于openssl pkcs12-nodes 选项仅在以下部分列出:

    解析PKCS12文件的选项如下:

    但是你不是在解析这样一个文件,你是在创建它,如果你看一下

    创建PKCS12文件的选项如下:

    甚至没有列出选项-nodes

    在提示输入密码时按回车也不会表示“无密码”,而是表示“空密码”(您的密码是空字符串),这是合法的。这在某些情况下就像没有密码一样工作的原因是某些软件会首先尝试使用空字符串密码读取 PKCS#12 文件,并且只有在失败时才会提示用户输入实际密码,所以如果密码为空,在这些情况下,用户不会被提示,看起来像是设置了“无密码”。

    这可能会导致 macOS 和 iOS 出现问题,因为 Apple 假定 PKCS#12 始终设置密码并且不允许您输入“空密码”,因此如果文件设置了空密码,则无法在这些系统上导入它。 Firefox 一开始也有这个问题,但是it was fixed 13 years ago.

    在读取 PKCS#12 文件时,OpenSSL 本身尝试仅通过猜测来区分“无密码”和“空密码”。这是该项目的原始代码:

     /* If we enter empty password try no password first */
     if(!mpass[0] && PKCS12_verify_mac(p12, NULL, 0)) {
         /* If mac and crypto pass the same set it to NULL too */
         if(!twopass) cpass = NULL;
     } else if (!PKCS12_verify_mac(p12, mpass, -1)) {
         BIO_printf (bio_err, "Mac verify error: invalid password?\n");
         ERR_print_errors (bio_err);
         goto end;
     }
    

    第一次传递NULL作为密码,第二次解析空字符串作为密码。现在我们看一下创建P12文件时的代码:

     p12 = PKCS12_create(cpass, name, key, ucert, certs,
                 key_pbe, cert_pbe, iter, -1, keytype);
    

    理论上,如果cpassNULL,则此调用将创建一个没有密码的PKCS#12 文件,但是,在进行此调用时,它不能是NULL,因为如果您从一开始就遵循代码路径对于上面调用的函数,没有代码路径会导致 cpass 最终成为 NULL

     if(!cpass) {
         if(export_cert) cpass = passout;
         else cpass = passin;
     }
    
     if(cpass) {
       mpass = cpass;
       noprompt = 1;
     } else {
       cpass = pass;
       mpass = macpass;
     }
    

    如果cpass最后还是NULLif,它将被设置为passpass是:

    char pass[50], macpass[50];
    

    这是一个静态变量,当存储到一个指针时,这个指针不能是NULL。没有其他代码会为cpass 分配不同的值,因此cpass 可以是空字符串,但它绝对不能是NULL

    实际加密发生在名为PKCS12_add_safe_ex() 的函数中,如果查看此函数,您会看到以下代码:

        if (nid_safe == 0)
    #ifdef OPENSSL_NO_RC2
            nid_safe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
    #else
            nid_safe = NID_pbe_WithSHA1And40BitRC2_CBC;
    #endif
    
        if (nid_safe == -1)
            p7 = PKCS12_pack_p7data(bags);
        else
            p7 = PKCS12_pack_p7encdata_ex(nid_safe, pass, -1, NULL, 0, iter, bags, ctx, propq);
        if (p7 == NULL)
            goto err;
    

    nid_safe 是一个数字,告诉函数使用哪种加密方法。如您所见,如果未设置(0 的值),则使用默认值,即 RC2,如果不可用,则使用 3DES。

    但是,如果nid_safe-1,这意味着NONE,则正在使用替代函数并且pass 甚至没有传递给该函数,因此pass 的值完全不相关案子。因此,您可以提供任何您喜欢的密码,如果您将密钥和证书的加密算法设置为NONE,则不会加密任何内容。

    【讨论】:

    • Mecki,仅使用 OpenSSL 命令行实用程序就可以生成未加密的 PKCS12 文件!详情请看我的回答stackoverflow.com/a/62863490/7878845。当key_pbecert_pbe 都设置为-1 时,传递给PKCS12_create() 的变量cpass 将被忽略,这可以通过命令行参数NONE 来实现。
    【解决方案3】:

    要仅使用 OpenSSL 命令行实用程序生成未加密的 PKCS12 文件,请调用以下命令:

    $ openssl pkcs12 -export -keypbe NONE -certpbe NONE -nomaciter -passout pass: -out bundle.pfx -inkey mykey.key -in certificate.crt -certfile ca-cert.crt
    

    当私钥 (-keypbe) 和证书 (-certpbe) 的加密算法设置为 NONE 时,openssl 的 pkcs12 库将忽略密码参数并且不加密私钥和证书。

    这可以通过openssl pkcs12 -info命令验证:

    $ openssl pkcs12 -info -in bundle.pfx -noout -passin pass:
    MAC: sha1, Iteration 1
    MAC length: 20, salt length: 8
    PKCS7 Data
    Certificate bag
    Certificate bag
    PKCS7 Data
    Key bag
    

    请注意,使用 openssl 命令行工具读取现有 PKCS12 文件时,即使数据未加密,也需要指定 -passin pass: 参数。这是因为 openssl 命令行工具无法检测 PKCS12 文件是否加密。当指定空密码时,openssl 首先尝试读取未加密的文件。如果失败,则 openssl 尝试读取该文件,并使用空密码加密。

    当我生成 bundle.pfx 而不指定 -keypbe NONE -certpbe NONE -nomaciter 参数时,openssl pkcs12 -info 显示如下:

    $ openssl pkcs12 -info -in bundle.pfx -noout -passin pass:
    MAC: sha1, Iteration 2048
    MAC length: 20, salt length: 8
    PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2048
    Certificate bag
    PKCS7 Data
    Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
    

    所以在这种情况下数据是用空密码加密的。

    【讨论】:

      【解决方案4】:

      在需要为openconnect 转换证书时遇到同样的问题

      需要额外的步骤才能在没有密码的情况下完成

      openssl rsa -in private.key -out private.nopwd.key
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-17
        • 2010-10-07
        • 2011-08-20
        • 1970-01-01
        • 2019-05-28
        • 1970-01-01
        • 2019-10-22
        • 1970-01-01
        相关资源
        最近更新 更多