创建截止日期为过去的自签名证书


24

我想即时创建带有任意开始日期和结束日期(包括过去的结束日期)的自签名证书。我更喜欢使用标准工具,例如OpenSSL,但是任何可以完成工作的工具都很棒。

堆栈溢出问题如何生成有效期少于一天的openssl证书?问类似的问题,但我希望我的证书可以自签名。

如果您想知道,证书是自动化测试所必需的。

Answers:


32

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

1)首先,关于伪造的时间:做一个节目觉得是从系统中不同的日期,看看libfaketimefaketime

要在Debian中安装它:

sudo apt-get install faketime

然后,您将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

来自man faketime

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

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

faketime '2008-12-24 08:15:42' openssl ... 

附带说明一下,该实用程序可以在包括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

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."
     */

并且来自CHANGE日志(错误2038吗?)-此更改日志仅作为一个附加脚注,因为它只涉及那些直接使用API​​的用户。

在1.1.0e和1.1.1之间更改[xx XXX xxxx]

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

因此,创建从2008年1月1日到2010年1月1日的证书的过程如下:

openssl ca -config /path/to/myca.conf -in req.csr -out ourdomain.pem \
-startdate 200801010000Z -enddate 201001010000Z

要么

openssl ca -config /path/to/myca.conf -in req.csr -out ourdomain.pem \
-startdate 0801010000Z -enddate 1001010000Z

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

报价openssl/CHANGE

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

*)将-startdate和-enddate(缺少)参数固定为“ ca”程序。

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


1
+1。我知道有人会带来比我写的要好的东西:)
Celada

2
还有一个类似的程序叫做datefudge
Wyzard-停止Harming Monica--

@Wyzard谢谢,的确,我在Debian中找到了它;有趣的是,该手册指出,尽管它还将系统调用更改为诸如time(2)之类的函数,但它不会影响fstat(2)。
Rui F Ribeiro

1
无论faketimedatefudge做工精美,我的Debian杰西系统。
rlandster '17

1
OTOH:+5,用于查找在何处设置这些日期!
guntbert

8

我发现这一显而易见的事情行之有效,我几乎感到惊讶:虽然openssl以证书应有效的天数作为参数,但只需提供一个负数!

openssl req -x509 -newkey rsa:4096 \
    -keyout key.pem -out cert.pem -days -365

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


好吧,公平地说,我不知道您可以使用消极的日子。
Rui F Ribeiro

您不能指定开始日期吗?
FreeSoftwareServers

@FreeSoftwareServers在CSR中,您不能;看到我答案的最后一部分。
Rui F Ribeiro

更有趣的是,代码Barf是否会找到这样的证书?顺便说一句,我扩大了答案
Rui F Ribeiro

3

或者,您可以使用类似此简短的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))

该代码似乎缺少必不可少的X.509标准字段。
Rui F Ribeiro

2
这非常有帮助。它使我可以更轻松地对证书创建进行程序控制。
rlandster '17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.