创建结束日期为过去的自签名证书

rla*_*ter 30 openssl certificates

我想动态创建具有任意开始和结束日期的自签名证书,包括过去的结束日期。我更喜欢使用标准工具,例如 OpenSSL,但任何能完成工作的东西都会很棒。

Stack Overflow 问题如何生成不到一天到期的 openssl 证书?问了一个类似的问题,但我希望我的证书是自签名的。

如果您想知道,自动化测试需要证书。

Rui*_*iro 39

过去您有两种创建证书的方法。要么伪造时间(1)(2),要么在签署证书时定义时间间隔(3)。

1)首先,关于伪造时间:让一个程序认为它与系统在不同的日期,看看libfaketimefaketime

要在 Debian 中安装它:

sudo apt-get install faketime
Run Code Online (Sandbox Code Playgroud)

然后您将faketimeopenssl命令之前使用。

使用示例:

$faketime 'last friday 5 pm' /bin/date
Fri Apr 14 17:00:00 WEST 2017
$faketime '2008-12-24 08:15:42' /bin/date
Wed Dec 24 08:15:42 WET 2008
Run Code Online (Sandbox Code Playgroud)

来自man faketime

给定的命令将被欺骗相信当前系统时间是时间戳中指定的时间。除非另有说明,挂钟将从此日期和时间继续运行(请参阅高级选项)。实际上,faketime 是 libfaketime 的一个简单包装器,它使用 LD_PRELOAD 机制加载一个小型库,该库拦截对 time(2) 和 fstat(2) 等函数的系统调用。

因此,例如,在您的情况下,您可以很好地定义 2008 年的日期,然后创建有效期为 2 年至 2010 年的证书。

faketime '2008-12-24 08:15:42' openssl ... 
Run Code Online (Sandbox Code Playgroud)

附带说明一下,该实用程序可以在包括 MacOS 在内的多个 Unix 版本中用作任何类型程序的包装器(不限于命令行)。

作为澄清,只有使用此方法加载的二进制文件(及其子文件)才会更改时间,并且假时间不会影响系统其余部分的当前时间。

2)正如@Wyzard 所述,您还有datefudge一个与faketime.

作为差异,datefudge不影响fstat(即不改变文件时间创建)。它还有自己的库 datefudge.so,它使用 LD_PRELOAD 加载。

它还有一个 -s static time总是返回引用的时间,尽管已经过去了多少秒。

$ datefudge --static "2007-04-01 10:23" sh -c "sleep 3; date -R"
Sun, 01 Apr 2007 10:23:00 +0100
Run Code Online (Sandbox Code Playgroud)

3)除了伪造时间,更简单的是,您还可以在OpenSSL中签署证书时定义证书有效性的起点和终点。

您在问题中链接到的问题的误解是,证书有效性不是在请求时(在 CSR 请求时)定义的,而是在签名时定义的。

当使用openssl ca创建自签名证书,添加的选项-startdate-enddate

这两个选项中的日期格式,根据 openssl 的来源openssl/crypto/x509/x509_vfy.c,是 ASN1_TIME 又名 ASN1UTCTime:格式必须是 YYMMDDHHMMSSZ 或 YYYYMMDDHHMMSSZ。

引用openssl/crypto/x509/x509_vfy.c

int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
{
    static const size_t utctime_length = sizeof("YYMMDDHHMMSSZ") - 1;
    static const size_t generalizedtime_length = sizeof("YYYYMMDDHHMMSSZ") - 1;
    ASN1_TIME *asn1_cmp_time = NULL;
    int i, day, sec, ret = 0;

    /*
     * Note that ASN.1 allows much more slack in the time format than RFC5280.
     * In RFC5280, the representation is fixed:
     * UTCTime: YYMMDDHHMMSSZ
     * GeneralizedTime: YYYYMMDDHHMMSSZ
     *
     * We do NOT currently enforce the following RFC 5280 requirement:
     * "CAs conforming to this profile MUST always encode certificate
     *  validity dates through the year 2049 as UTCTime; certificate validity
     *  dates in 2050 or later MUST be encoded as GeneralizedTime."
     */
Run Code Online (Sandbox Code Playgroud)

来自更改日志(2038 错误?) - 此更改日志只是一个附加脚注,因为它只涉及那些直接使用 API 的人。

1.1.0e 和 1.1.1 [xx XXX xxxx] 之间的变化

*) 添加 ASN.1 类型 INT32、UINT32、INT64、UINT64 和前缀为 Z 的变体。这些旨在替换 LONG 和 ZLONG 并确保大小安全。不鼓励使用 LONG 和 ZLONG,并计划在 OpenSSL 1.2.0 中弃用。

因此,创建从 2008 年 1 月 1 日到 2010 年 1 月 1 日的证书,可以这样做:

openssl ca -config /path/to/myca.conf -in req.csr -out ourdomain.pem \
-startdate 200801010000Z -enddate 201001010000Z
Run Code Online (Sandbox Code Playgroud)

或者

openssl ca -config /path/to/myca.conf -in req.csr -out ourdomain.pem \
-startdate 0801010000Z -enddate 1001010000Z
Run Code Online (Sandbox Code Playgroud)

-startdate并且-enddate确实出现在openssl源和更改日志中;正如@guntbert 所指出的,虽然它们没有出现在man openssl主页中,但它们也出现在man ca

-startdate date
       this allows the start date to be explicitly set. The format of the date is
       YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure).

   -enddate date
       this allows the expiry date to be explicitly set. The format of the date is
       YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure).
Run Code Online (Sandbox Code Playgroud)

引用openssl/CHANGE

0.9.3a 和 0.9.4 之间的变化 [1999 年 8 月 9 日]

*) 修复“ca”程序的 -startdate 和 -enddate(缺少)参数。

PS 至于您从 StackExchange 引用的问题的选择答案:更改系统时间通常是一个坏主意,尤其是在生产系统中;并且使用此答案中的方法,您在使用它们时不需要 root 权限。

  • 还有一个类似的程序叫做“datefudge”。 (2认同)

Cel*_*ada 10

我几乎惊讶地发现显而易见的事情是有效的:而openssl将证书应该有效的天数作为参数,只需提供一个负数!

openssl req -x509 -newkey rsa:4096 \
    -keyout key.pem -out cert.pem -days -365
Run Code Online (Sandbox Code Playgroud)

请注意,这实际上会导致一些非常奇怪的事情:证书的到期时间戳其有效期开始时间戳之前。我实际上不建议您将其用于自动化测试,因为它很奇怪。您可能还需要一种方法来回溯有效期开始的时间戳。


Edh*_*dil 5

或者你可以使用类似这个简短的 python 程序的东西......(注意事项适用)

它创建一个密钥(test.key)和一个证书(test.crt),其起始时间为过去10年(-10*365*24*60*60秒为-10年),过期时间为过去5年(-5*365*24*60*60)。

请注意,这是一个最小的演示程序,因此它不需要设置任何扩展(例如 basicConstraints)并使用固定串行。

#!/usr/bin/env python

from OpenSSL import crypto

key = crypto.PKey()
key.generate_key(crypto.TYPE_RSA, 2048)
cert = crypto.X509()
cert.get_subject().CN = "Test"
cert.set_serial_number(666)
cert.gmtime_adj_notBefore(-10*365*24*60*60)
cert.gmtime_adj_notAfter(-5*365*24*60*60)
cert.set_issuer(cert.get_subject())
cert.set_pubkey(key)
cert.sign(key, 'sha384')

open("test.crt", "wb").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
open("test.key", "wb").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
Run Code Online (Sandbox Code Playgroud)

  • 这非常有帮助。它使我能够更轻松地对证书创建进行编程控制。 (3认同)