深入理解时间戳
深入理解时间戳
时间戳可谓数字签名的好伙伴,它为数字签名提供了额外的时间上的保证,使得数字签名的可信度大大提高。
到底什么是时间戳?从PDF签名的角度来看,时间戳会直接表现在签名里:
在前两篇文章,我分析过PDF里的签名信息,也就是PDF dictionary里的content下的内容,其实是一个CMS对象. 而真正的签名值,也就是对一个哈希内容做的加密结果,其实是存在signerInfo下面的signature字段里。
PDF签名的时间戳对象,其实就是这个签名值signature.
时间戳的定义(wiki):
Trusted timestamping is the process of securely keeping track of the creation and modification time of a document. Security here means that no one—not even the owner of the document—should be able to change it once it has been recorded provided that the timestamper’s integrity is never compromised.
下面通过一个实例来说说整个时间戳请求和响应的过程。
1.生成TimeStampRequest
笔者想对字符串"123"做时间戳,首先对原文123做SHA256,得到数据指纹:
hex:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3
base64:pmWkWSBCL51Bfkhn79xPuKBKHz//H6B+mY6G9/eieuM=
得到了数据指纹,这里采用Java的第三方安全库bouncycastle来生成一个TimeStampRequest:
byte[] respBytes = null;
// Setup the time stamp request
TimeStampRequestGenerator tsqGenerator = new TimeStampRequestGenerator();
tsqGenerator.setCertReq(true);
if (tsaReqPolicy != null && tsaReqPolicy.length() > 0) {
tsqGenerator.setReqPolicy(new ASN1ObjectIdentifier(tsaReqPolicy));
}
// tsqGenerator.setReqPolicy("1.3.6.1.4.1.601.10.3.1");
BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis());
TimeStampRequest request = tsqGenerator.generate(new ASN1ObjectIdentifier(DigestAlgorithms.getAllowedDigests("SHA256")), tsImprint, nonce);
byte[] requestBytes = request.getEncoded();
TimeStampRequest的结构定义在RFC3161中:
其中messageImprint则是数据指纹,它包含了哈希算法和哈希值:
certReq则指示证书是否出现在SignedData的certificate字段中;nonce是一个代表时间的大数,会在response中带回。
2.向时间戳服务器发送请求
// Call the communications layer
respBytes = getTSAResponse(requestBytes);
// Handle the TSA response
TimeStampResponse response = new TimeStampResponse(respBytes);
response.validate(request);
System.out.println("base64 respBytes:\n" + new String(Base64.encode(respBytes), "UTF-8"));
System.out.println(response.getStatus());
System.out.println(response.getStatusString());
这里调用TSAClientBouncyCastle类封装好的getTSAResponse函数来得到响应结果:
base64 respBytes:
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
0
Operation Okay
3.解析TimeStampResponse
然后对TimeStampResponse进行解析。
如上图,RFC3161中定义的TimeStampResp的结构中包含一个status,指示结果的状态码,本例中状态码返回为0,表示成功。另一个是TimeStampToken结构:
TimeStampToken是SignedData类型的ContentInfo,看过前几篇文章的同学肯定记得,PDF签名也是一个SignedData类型。
我们从Response里把TimeStampToken解析出来:
TimeStampToken tst = response.getTimeStampToken();
TimeStampToken的结构定义可以参考系列文章之二. SignedData结构中包含的eContent其实是原始数据。对于PDF数字签名来说,eContent一般为空,则代表detached signature,也就是表示被签名的原始数据在“签名”之外。对于TimeStampToken来说,eContent里是一个TSTInfo类型数据:
我们可以看见与时间戳有关的信息都在这些字段里,包括原始的数据指纹messageImprint,时间戳产生时间genTime,流水号SerialNumber,透传参数nonce,精度accuracy等等。
TimeStampTokenInfo tsti = tst.getTimeStampInfo();
Date data = tsti.getGenTime();
System.out.println(data.toString());
System.out.println("tsti:hex\n" + org.apache.commons.codec.binary.Hex.encodeHexString(tsti.getEncoded()));
MessageDigest digest2 = MessageDigest.getInstance("SHA-256");
byte[] encodedhash2 = digest2.digest(tsti.getEncoded());
System.out.println("hash of tsti:hex\n" + org.apache.commons.codec.binary.Hex.encodeHexString(encodedhash2));
我们把TSTInfo对象解析出来,打印时间戳时间,并且把TSTInfo对象的原始二进制打印出来:
Thu Mar 08 10:25:40 CST 2018
tsti:hex
3067020101060c2b0601040181af080102032d3031300d060960864801650304020105000420a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae30208297eca7161e78d7f180f32303138303330383032323534305a02060162036da0b2
hash of tsti:hex
95cf776dcd5db22133c53e76ccb99a321f652581427ee1e74b055ceb54325d3a
因为后面会用到,我们在这里把TSTInfo的哈希值算出来了。
下面来分析一下时间戳服务器的签名。
在前面我们讲到PDF真正的签名值在SignedData下SignerInfo的Signature里,那么TimeStampToken也不例外,因为它也是一个SignedData类型。
与PDF签名一致,TimeStampToken也只允许一个签名值,也就是只存在一个SignerInfo,签名者是时间戳服务器。我们可以把时间戳服务器的签名证书解析出来:
Store store = tst.getCertificates();
SignerId sid = tst.getSID();
X509CertificateHolder cert = (X509CertificateHolder)store.getMatches(sid).iterator().next();
byte[] array = cert1.getEncoded();
System.out.println("cert: " + new String(Base64.encode(array), "UTF-8"));
从TimeStampInfo里得到证书列表,然后根据SignerInfo里的CertID找到该证书
cert: MIIFCjCCA/KgAwIBAgIIVAnE5PcrHMcwDQYJKoZIhvcNAQELBQAwbzELMAkGA1UEBhMCQ04xOTA3BgNVBAoMMEdsb2JhbCBEaWdpdGFsIEN5YmVyc2VjdXJpdHkgQXV0aG9yaXR5IENvLiwgTHRkLjElMCMGA1UEAwwcR0RDQSBUcnVzdEFVVEggUjQgR2VuZXJpYyBDQTAeFw0xNzA0MTMwNjQwMDZaFw0yNzA0MTEwNjQwMDZaMIGEMQswCQYDVQQGEwJDTjESMBAGA1UECAwJ5bm/5Lic55yBMRIwEAYDVQQHDAnlub/lt57luIIxLTArBgNVBAsMJOaVsOWuieaXtuS7o+enkeaKgOiCoeS7veaciemZkOWFrOWPuDEeMBwGA1UEAwwVR0RDQSBUaW1lc3RhbXAgU2lnbmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4wC9fArtnGSuKjGVtJgJ98ou5moCPVnv2dar9nkk0FLZ2105P2jfU6aT1BHcvk1k6cmjOKUyGfz5FBn06eF+e26y/l25tzzQn/ZRMfAelFWEmRbXNlOn54B5njJAdYNQU7IM/ufKYLzBjuqMdZy9de66/m5ExuXJThUh7Bf2K6T3aQePnv6XIJ9i6DztCbXwfyGRYf+jHWOrNItVl7QImcwoUR+Afa3x+d+zkc8HZuSCXMDiKm3WrmjzfLdkawzANLV7bxTKzCKfkoIXdVUFJabjZamthk6ksLi33g3N6TMPTNrBHGp/y9Yt8bCwPbTwV3byS+BH7kL/KNJSTbDjtQIDAQABo4IBkjCCAY4wgYMGCCsGAQUFBwEBBHcwdTBIBggrBgEFBQcwAoY8aHR0cDovL3d3dy5nZGNhLmNvbS5jbi9jZXJ0L0dEQ0FfVHJ1c3RBVVRIX1I0X0dlbmVyaWNfQ0EuZGVyMCkGCCsGAQUFBzABhh1odHRwOi8vb2NzcDIuZ2RjYS5jb20uY24vb2NzcDAdBgNVHQ4EFgQUAn2SnDTJycvFLNlKHleiM9XoioYwCQYDVR0TBAIwADAfBgNVHSMEGDAWgBTT/u5hgMCZkFlt1iRV8v/A6ycX7DBFBgNVHSAEPjA8MDoGCiqBHIbvLwEBAQIwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3dy5nZGNhLmNvbS5jbi9jcHMvY3BzMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuZ2RjYS5jb20uY24vY3JsL0dEQ0FfVHJ1c3RBVVRIX1I0X0dlbmVyaWNfQ0EuY3JsMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQsFAAOCAQEAqEWGYzFE58FpByBwPQDnU3KzvWyPdMIhd726SRjiOMIecjBqXpd0fi3KJ3+rq/oCT8N8gSIezEzcXVPdJ2oCnHFaBZCUJOndvoOK1GM20oEnNnEYLvG6iilyAy5lDPqjbpmMYC6Hk4h8bnPMhUQNpDqEjpYKyisoN0dQh0viXPwmojahM+1CsYOlirC4NwTJVhcNA8ssB1Z74fGrNx+cSH7scA1IqTzVygtYUJ7MqQ5atXQw/ji0Ofu4m4yRR+3fnjG3l23zmXH/WehlzY4kuilhHBhD39N4WV7+a99JUoiqj8Ao/hTjz7rVdOX9M1Zj4Tj1zWE1QDN02eNdwEql+w==
得到证书的base64 code我们就可以解析证书信息了,这里不展开说明。
系列文章二说过,对于SignedData类型而言,真正的签名对象,其实是SignerInfo里的SignedAttributes, 对于TimeStampToken, 我们也来解析一下SignedAttributes里的信息:
AttributeTable at = tst.getSignedAttributes();
System.out.println(at.size());
Attributes attri = at.toASN1Structure();
Attribute[] attris = attri.getAttributes();
System.out.println(attris.length);
ASN1ObjectIdentifier asn1oid = attris[0].getAttrType();
System.out.println(asn1oid.getId());
ASN1Set asn1sets = attris[0].getAttrValues();
System.out.println(asn1sets.toString());
5
1.2.840.113549.1.9.4
[#95cf776dcd5db22133c53e76ccb99a321f652581427ee1e74b055ceb54325d3a]
1.2.840.113549.1.9.3
[1.2.840.113549.1.9.16.1.4]
1.2.840.113549.1.9.52
[[[2.16.840.1.101.3.4.2.1, NULL], [1][1.2.840.113549.1.1.1, NULL]]]
1.2.840.113549.1.9.16.2.47
[[[[#73235f031d653eb284dd9e735f082f4642afc783db26bb3caf21db89af131274, [[[4][[[2.5.4.6, CN]], [[2.5.4.10, Global Digital Cybersecurity Authority Co., Ltd.]], [[2.5.4.3, GDCA TrustAUTH R4 Generic CA]]]], 6055587661654727879]]]]]
1.2.840.113549.1.9.5
[180308022540Z]
SignedAttributes里包含五个属性,第一个是MessageDigest, 我们打印出来的结果与上文中tsti的哈希值相同,说明这里的哈希值原文就是TSTInfo数据。另外的属性有证书信息,时间信息,算法信息,类型信息。对这些信息进行签名,得到了SignerInfo里的签名值Signature.
我们可以取得SignerInfo里SignedAttributes的二进制值和Signature的值,然后使用之前得到的证书进行公钥验证,验证结果正确。
签名原文:
byte[] encodedSignedAttri = signer.getEncodedSignedAttributes();
System.out.println("encodedSignedAttri in signer infobase64:\n" + new String(Base64.encode(encodedSignedAttri), "UTF-8"));
encodedSignedAttri in signer infobase64:
MYIBWTAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTE4MDMwODAyMjU0MFowLQYJKoZIhvcNAQk0MSAwHjANBglghkgBZQMEAgEFAKENBgkqhkiG9w0BAQEFADAvBgkqhkiG9w0BCQQxIgQglc93bc1dsiEzxT52zLmaMh9lJYFCfuHnSwVc61QyXTowgbwGCyqGSIb3DQEJEAIvMYGsMIGpMIGmMIGjBCBzI18DHWU+soTdnnNfCC9GQq/Hg9smuzyvIduJrxMSdDB/MHOkcTBvMQswCQYDVQQGEwJDTjE5MDcGA1UECgwwR2xvYmFsIERpZ2l0YWwgQ3liZXJzZWN1cml0eSBBdXRob3JpdHkgQ28uLCBMdGQuMSUwIwYDVQQDDBxHRENBIFRydXN0QVVUSCBSNCBHZW5lcmljIENBAghUCcTk9yscxw==
签名值:
byte[] signature = signer.getSignature();
System.out.println("signature in signer info:\n" + new String(Base64.encode(signature), "UTF-8"));
signature in signer info:
j19ixgzVsAg+IAfRdfvfSpbkq57FhT6oDyHwSwJAh3oPLdfNOHawkVoDy5Kd08DfcpWQI7NsqwqZ3TTc+qHqnjQWicAsJd7yHN7rJ9W6PY/UB1ddgZ1f78ZL6R8i6ewZWOR2h4w2iBXLuvOlvd1QQ6W4CtILxZET8MoDS8460ln6AVKi/nDIjz5T4mybvv9kLzpxSuVIb+93ArN3auVieuVFYkNnF0t01/sOzX3t5vtRB3HOrtHu1bH5zWWnlQkn82dSz9I23liOWO5pdI3NsM1KgQLyV4et+YFcuQft9qUauxQiSCH9CBc8yUzIK3aepU1C6b1DnsUsM8XL7n7WmA==
验证过程就不详述,笔者验证通过。
实验到这里就结束了。因为工作需要,笔者对数字签名和时间戳做了很底层很深入的研究,这个课题现在越来越普及了,但是网上讲得清楚且通俗的资料却很少,笔者记录下自己的一些研究发现,为将来做一个笔记备份,也为正在入门数字签名开发的伙伴提供一些参考。