- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我的构建过程中,我想包含来自符合 RFC-3161 的 TSA 的时间戳。在运行时,代码将验证这个时间戳,最好不需要第三方库的帮助。 (这是一个 .NET 应用程序,因此我可以随时使用标准哈希和非对称加密功能。)
RFC 3161,它依赖于 ASN.1 和 X.690 等等,实现起来并不简单,所以至少现在,我使用 Bouncy CaSTLe 来生成 TimeStampReq(请求)并解析 TimeStampResp(响应)。我只是无法弄清楚如何验证响应。
到目前为止,我已经弄清楚了如何提取签名本身、公共(public)证书、创建时间戳的时间以及我发送的消息印记摘要和随机数(用于构建时验证)。我不知道如何将这些数据放在一起以生成经过散列和签名的数据。
这是我正在做什么以及我正在尝试做什么的粗略想法。这是测试代码,所以我采取了一些捷径。一旦我得到一些有用的东西,我将不得不清理一些东西并以正确的方式做它们。
构建时生成时间戳:
// a lot of fully-qualified type names here to make sure it's clear what I'm using
static void WriteTimestampToBuild(){
var dataToTimestamp = Encoding.UTF8.GetBytes("The rain in Spain falls mainly on the plain");
var hashToTimestamp = new System.Security.Cryptography.SHA1Cng().ComputeHash(dataToTimestamp);
var nonce = GetRandomNonce();
var tsr = GetTimestamp(hashToTimestamp, nonce, "http://some.rfc3161-compliant.server");
var tst = tsr.TimeStampToken;
var tsi = tst.TimeStampInfo;
ValidateNonceAndHash(tsi, hashToTimestamp, nonce);
var cms = tst.ToCmsSignedData();
var signer =
cms.GetSignerInfos().GetSigners()
.Cast<Org.BouncyCastle.Cms.SignerInformation>().First();
// TODO: handle multiple signers?
var signature = signer.GetSignature();
var cert =
tst.GetCertificates("Collection").GetMatches(signer.SignerID)
.Cast<Org.BouncyCastle.X509.X509Certificate>().First();
// TODO: handle multiple certs (for one or multiple signers)?
ValidateCert(cert);
var timeString = tsi.TstInfo.GenTime.TimeString;
var time = tsi.GenTime; // not sure which is more useful
// TODO: Do I care about tsi.TstInfo.Accuracy or tsi.GenTimeAccuracy?
var serialNumber = tsi.SerialNumber.ToByteArray(); // do I care?
WriteToBuild(cert.GetEncoded(), signature, timeString/*or time*/, serialNumber);
// TODO: Do I need to store any more values?
}
static Org.BouncyCastle.Math.BigInteger GetRandomNonce(){
var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
var bytes = new byte[10]; // TODO: make it a random length within a range
rng.GetBytes(bytes);
return new Org.BouncyCastle.Math.BigInteger(bytes);
}
static Org.BouncyCastle.Tsp.TimeStampResponse GetTimestamp(byte[] hash, Org.BouncyCastle.Math.BigInteger nonce, string url){
var reqgen = new Org.BouncyCastle.Tsp.TimeStampRequestGenerator();
reqgen.SetCertReq(true);
var tsrequest = reqgen.Generate(Org.BouncyCastle.Tsp.TspAlgorithms.Sha1, hash, nonce);
var data = tsrequest.GetEncoded();
var webreq = WebRequest.CreateHttp(url);
webreq.Method = "POST";
webreq.ContentType = "application/timestamp-query";
webreq.ContentLength = data.Length;
using(var reqStream = webreq.GetRequestStream())
reqStream.Write(data, 0, data.Length);
using(var respStream = webreq.GetResponse().GetResponseStream())
return new Org.BouncyCastle.Tsp.TimeStampResponse(respStream);
}
static void ValidateNonceAndHash(Org.BouncyCastle.Tsp.TimeStampTokenInfo tsi, byte[] hashToTimestamp, Org.BouncyCastle.Math.BigInteger nonce){
if(tsi.Nonce != nonce)
throw new Exception("Nonce doesn't match. Man-in-the-middle attack?");
var messageImprintDigest = tsi.GetMessageImprintDigest();
var hashMismatch =
messageImprintDigest.Length != hashToTimestamp.Length ||
Enumerable.Range(0, messageImprintDigest.Length).Any(i=>
messageImprintDigest[i] != hashToTimestamp[i]
);
if(hashMismatch)
throw new Exception("Message imprint doesn't match. Man-in-the-middle attack?");
}
static void ValidateCert(Org.BouncyCastle.X509.X509Certificate cert){
// not shown, but basic X509Chain validation; throw exception on failure
// TODO: Validate certificate subject and policy
}
static void WriteToBuild(byte[] cert, byte[] signature, string time/*or DateTime time*/, byte[] serialNumber){
// not shown
}
// a lot of fully-qualified type names here to make sure it's clear what I'm using
static void VerifyTimestamp(){
var timestampedData = Encoding.UTF8.GetBytes("The rain in Spain falls mainly on the plain");
var timestampedHash = new System.Security.Cryptography.SHA1Cng().ComputeHash(timestampedData);
byte[] certContents;
byte[] signature;
string time; // or DateTime time
byte[] serialNumber;
GetDataStoredDuringBuild(out certContents, out signature, out time, out serialNumber);
var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(certContents);
ValidateCert(cert);
var signedData = MagicallyCombineThisStuff(timestampedHash, time, serialNumber);
// TODO: What other stuff do I need to magically combine?
VerifySignature(signedData, signature, cert);
// not shown: Use time from timestamp to validate cert for other signed data
}
static void GetDataStoredDuringBuild(out byte[] certContents, out byte[] signature, out string/*or DateTime*/ time, out byte[] serialNumber){
// not shown
}
static void ValidateCert(System.Security.Cryptography.X509Certificates.X509Certificate2 cert){
// not shown, but basic X509Chain validation; throw exception on failure
}
static byte[] MagicallyCombineThisStuff(byte[] timestampedhash, string/*or DateTime*/ time, byte[] serialNumber){
// HELP!
}
static void VerifySignature(byte[] signedData, byte[] signature, System.Security.Cryptography.X509Certificates.X509Certificate2 cert){
var key = (RSACryptoServiceProvider)cert.PublicKey.Key;
// TODO: Handle DSA keys, too
var okay = key.VerifyData(signedData, CryptoConfig.MapNameToOID("SHA1"), signature);
// TODO: Make sure to use the same hash algorithm as the TSA
if(!okay)
throw new Exception("Timestamp doesn't match! Don't trust this!");
}
MagicallyCombineThisStuff
功能。
最佳答案
恭喜你完成了那个棘手的协议(protocol)工作!
另请参阅 rfc3161ng 2.0.4 上的 Python 客户端实现。 .
请注意,使用 RFC 3161 TSP 协议(protocol),如 Web Science and Digital Libraries Research Group: 2017-04-20: Trusted Timestamping of Mementos 中所述和其他出版物,您和您的依赖方必须相信时间戳管理局 (TSA) 的操作正确且安全。当然,要真正保护大多数 TSA 运行的在线服务器,即使不是不可能,也是非常困难的。
正如该论文中所讨论的那样,通过与 TSP 的比较,现在世界上有各种各样的公共(public)区 block 链,其中信任分布和(有时)仔细监控,有新的可信时间戳选项(为文档提供“存在证明”) .例如见
OriginStamp - Trusted Timestamping with Bitcoin .该协议(protocol)要简单得多,并且它们为多种语言提供客户端代码。虽然他们的在线服务器也可能受到威胁,但客户端可以检查他们的哈希是否正确嵌入到比特币区 block 链中,从而绕过信任 OriginStamp 服务本身的需要。
一个缺点是时间戳每天只发布一次,除非支付额外费用。比特币交易变得相当昂贵,因此该服务正在考虑支持其他区 block 链,以降低成本并降低获得更及时发布的成本。
更新 :查看 Stellar 和 Keybase
如需免费、高效、闪电般快速且经过广泛审查的时间戳,请查看 Stellar 区 block 链协议(protocol)和 STELLARAPI.IO服务。
关于digital-signature - 验证 RFC 3161 可信时间戳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19528456/
我讨厌发布“这应该很容易,我错过了什么”问题,但是......这应该很容易,我错过了什么?我在这个测试代码上没有得到匹配,我不明白为什么。模式是(或应该是)“任何三个数字,后跟任何三个相同的数字,后跟
我在 digital ocean 上部署了一个应用程序,我想更新它的部署源 (github)。我将我的 github 存储库移到了一个组织,现在 digital ocean 似乎无法再访问它了。 我相
我在 digital ocean 上部署了一个应用程序,我想更新它的部署源 (github)。我将我的 github 存储库移到了一个组织,现在 digital ocean 似乎无法再访问它了。 我相
[抱歉,如果这不太适合 SO,Digits 的支持链接到 SO] 在我的 iOS 应用程序中,有些用户使用 Digits 登录,有些则不使用。我仍然希望能够通过 Digits 的联系人匹配使用他们的通
我有这样的查询: SELECT * FROMmesWHERE text REGEXP '#11' 我想获得#11 的所有含义,例如: #11 #11a 但不是数字后面有数字的情况: #112 所以我厌
我有一个 file.txt 看起来像这样: abe abbe cde 45a678 ae cababb 12345 在运行命令 egrep [[:digit:]] file.txt 之后它显示了两个结
我有一个生产服务器 - 一个 Digital Ocean Droplet - 上面运行着一个数据库和网站。我现在想继续制作一个临时服务器。我认为克隆它是一个好主意,但是执行此类操作的好方法是什么? 到
似乎 get.k8s.io 是部署 Kubernetes 集群的推荐方法,但该脚本不支持 Digital Ocean。 有没有一种我错过的替代方法可以在 Digital Ocean 上轻松设置集群?
我有关于 java 正则表达式的查询。实际上,我是正则表达式的新手。所以我需要帮助来为下面的语句形成一个正则表达式: Statement: a-alphanumeri
我对大家有一些特殊的要求。我需要对以下对象数组进行自定义顺序/排序。我需要订购的数组可能类似于以下示例: //array $scope.myArray = [ { orderI
我有一个数字 N。继续对数字求和,直到得到一位数字的结果。例如 35252 ==> 17 ==> 8我写了以下代码: int digitSum(int n) { int sum = 0;
我想允许用户输入以下十进制或整数值 (A) .5 0.500 3 0 0.0 30 500000 4000.22 0. 这是我使用的以下正则表达式: factor: /^-?\d*[.]??\d*$/
我正在使用if语句显示隐藏的div。用户只需按一下按钮即可循环选择他们想要预订的小时数。时间最多可达 10 小时。 if如果 checkHours 则语句会显示通知小于 5。一切都工作得很好,直到用户
如何编写正则表达式来验证此模式? 123456 - correct *1 - correct 1* - correct 124** - correct *1*2 - correct * - corre
所以这就是我想要做的。 在 git 中推送到 master 有 gitlab-ci 听说推送启动管道 管道构建代码并将 docker 容器推送到 gitlab 注册表 管道通过 ssh 登录到 d
myString.match("[\d]*") 对于 12345 和 77777 给出 true 但我正在寻找的结果是 12345 为 false,7777 为 true 最佳答案 (\d)\1*\D
在 iOS 应用程序中安装 Digits 1.15.1 时,AppDelegate.m 文件中出现以下错误: 无法在导入语句中构建模块“DigitsKit”#import 在 [Fabric wit
如何使正则表达式不匹配超过 2 位数的特定数字。例如除 13 以外的任何数字。下面的第二行代码将无法匹配 10、11...,第三行将查找不以 1 开头但具有 3 的数字: str = 'val=13'
我实际上有一个可能看起来很疯狂的问题,但在 WCF 中我有一个简单的契约(Contract),有时当我将 DataContract 设置为小数时,服务会在“.”之后发回 4 位数字。我其实很期待只有2
如果我执行以下操作: et_user_input.setKeyListener(DigitsKeyListener.getInstance("123-+")); et_user_input.setIn
我是一名优秀的程序员,十分优秀!