更新
我已经在StackExchange Code Review网站上发布了一个脚本,我正在使用它。
我的原始问题是是否有一种方法可以使用X.509证书和时间戳签署Git提交?有一段时间,我认为只有受信任的第三方才能为我签署的使用X.509证书签名的内容加上时间戳。这并不是事实。用X.509证书进行数字签名和信任时间戳是互相排斥的。我已经更新了我的问题以反映这一点。
正如VonC指出的,使用X.509证书对Git提交进行签名并没有任何价值。使用GPG密钥是更好的选择,因为Git具有内置支持。
我接受了Greg的答案,因为它最接近我所要求的,尽管我的原始问题有点模糊。正如Greg所指出的那样,如果你能证明你在某个时间点知道一个提交哈希值,那么就可以保证你在那个时间知道哈希值对应的存储库内容,并且不需要在存储库中存储任何额外的数据。时间戳数据可以存储在任何地方。
可以使用openssl
(v1.0.0+)和curl
请求RFC3161时间戳来获取提交哈希值的时间戳。
请求时间戳
您需要一些信息:
- URL - RFC3161时间戳服务
- REV - 您要获取时间戳的版本(哈希)。必须是完整的哈希。
CONTENT_TYPE="Content-Type: application/timestamp-query"
ACCEPT_TYPE="Accept: application/timestamp-reply"
openssl ts -query -cert -digest "$REV" -sha1 \
| curl -s -H "$CONTENT_TYPE" -H "$ACCEPT_TYPE" --data-binary @- $URL
上述代码将有符号时间戳输出到 stdout
。如果时间戳服务拒绝请求,它也可能输出错误消息。
验证时间戳
这与请求时间戳非常相似,但您还需要:
- CAFILE - 时间戳服务的证书链,返回到根CA
时间戳服务应该使用由受信任机构颁发的证书对时间戳进行签名。如果没有,您的时间戳就没有太多可信度。如果无法找到或创建正确的证书链,请尝试使用由 curl
发布的 cacert.pem
。它在这里。
下面的代码片段假设一个现有的、已签名的时间戳响应被传递给了 stdin
。应该可以直接将上面的请求导入到下面的验证命令中。如果将响应存储在变量中,则可能需要对其进行 base64 编码/解码 (man base64
)。
openssl ts -verify -digest "$REV" -in /dev/stdin -CAfile "$CAFILE"
如果您检查回复,您会注意到请求摘要与使用的Git修订版本相匹配。您可以使用此命令检查回复的纯文本版本。
openssl ts -reply -in /dev/stdin -text
这是一个回复的示例,我在顶部添加了Git版本。
--------------------------------------------------------------------------------
Revision: 871d715e5c072b1fbfacecc986f678214fa0b585
--------------------------------------------------------------------------------
Status info:
Status: Granted.
Status description: unspecified
Failure info: unspecified
TST info:
Version: 1
Policy OID: 1.3.6.1.4.1.6449.2.1.1
Hash Algorithm: sha1
Message data:
0000 - 87 1d 71 5e 5c 07 2b 1f-bf ac ec c9 86 f6 78 21 ..q^\.+.......x!
0010 - 4f a0 b5 85 O...
Serial number: 0xB2EA9485C1AFF55C6FFEDC0491F257C8393DB5DC
Time stamp: Aug 15 08:41:48 2012 GMT
Accuracy: unspecified
Ordering: no
Nonce: 0x615F0BF6FCBBFE23
TSA: DirName:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Time Stamping Signer
Extensions:
其他注意事项
许多时间戳服务要求用户在脚本签名请求中添加延迟。确保您了解所使用的服务是否需要。目前我使用的Comodo要求在脚本请求之间添加15秒延迟。我选择使用Comodo只是因为我从他们那里购买了代码签名证书。
Git笔记似乎是存储签名时间戳响应的明显选择,但我还没有完整的解决方案可以发布。我目前被卡在这个问题上。
下面是我的原始问题和更新内容。
我想要证明我进行的Git提交的时间,并证明我的存储库的历史记录没有被重写。它不必每次提交都这样做,每天或每周一次就足够了。是否有推荐的方法来实现这一点?
我知道我可以使用GPG密钥签署Git提交,但我想知道是否有一种方法可以使用X.509证书对我的提交进行签名,同时利用在线时间戳服务,例如 http://timestamp.comodoca.com/rfc3161。
如果没有,是否会每天使用git rev-parse --verify HEAD
将当前修订版本转储到文本文件中,签署该文件,并提交,足以证明(大约)我的代码何时编写?
补充信息以便更清晰理解
我知道Git保证存储库的完整性,但据我所知,如果我控制存储库,则第三方必须相信我没有重写存储库的历史记录或将我的时钟回滚并创建一个完全虚假的存储库,以“证明”我的代码比它实际上更旧?我也不想公开发布我的存储库。
以下是一个虚构的用例,应该能够更好地说明我想要做什么。
我在网上发布了一些代码。一年后,有人将相同的代码复制并发布到书籍或文章中,并声称我是复制他们的人。此时,我想能够拿出我的存储库并证明我一年前就提交了那段代码,而他们是重新发布它。
通过使用带有时间戳服务的X.509证书,我可以证明签名发生的时间。只要我能证明我知道一年前提交的哈希值,Git就保证了归档的完整性。
或者,是否有一种使用GPG密钥签名提交,但具有经过验证的时间戳的方法?是否有一个受信任的第三方提供类似X.509证书可用的时间戳服务,但用于GPG?
也许我可以结合使用GPG密钥和X.509证书。假设我在存储库中保留了我的(公共)GPG密钥的副本,如果我每天结束时都执行以下操作,是否有效?
- 使用我的X.509证书和在线时间戳服务对我的(公共)GPG密钥进行签名。
- 使用我的(私有)GPG密钥对更改进行签名,并将其提交到存储库。