init commit
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Tsp;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public class GenTimeAccuracy
|
||||
{
|
||||
private Accuracy accuracy;
|
||||
|
||||
public int Seconds => GetTimeComponent(accuracy.Seconds);
|
||||
|
||||
public int Millis => GetTimeComponent(accuracy.Millis);
|
||||
|
||||
public int Micros => GetTimeComponent(accuracy.Micros);
|
||||
|
||||
public GenTimeAccuracy(Accuracy accuracy)
|
||||
{
|
||||
this.accuracy = accuracy;
|
||||
}
|
||||
|
||||
private int GetTimeComponent(DerInteger time)
|
||||
{
|
||||
return time?.Value.IntValue ?? 0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Seconds + "." + Millis.ToString("000") + Micros.ToString("000");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Tsp;
|
||||
using Org.BouncyCastle.Asn1.X509;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.X509;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public class TimeStampRequest : X509ExtensionBase
|
||||
{
|
||||
private TimeStampReq req;
|
||||
|
||||
private X509Extensions extensions;
|
||||
|
||||
public int Version => req.Version.Value.IntValue;
|
||||
|
||||
public string MessageImprintAlgOid => req.MessageImprint.HashAlgorithm.Algorithm.Id;
|
||||
|
||||
public string ReqPolicy
|
||||
{
|
||||
get
|
||||
{
|
||||
if (req.ReqPolicy != null)
|
||||
{
|
||||
return req.ReqPolicy.Id;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public BigInteger Nonce
|
||||
{
|
||||
get
|
||||
{
|
||||
if (req.Nonce != null)
|
||||
{
|
||||
return req.Nonce.Value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CertReq
|
||||
{
|
||||
get
|
||||
{
|
||||
if (req.CertReq != null)
|
||||
{
|
||||
return req.CertReq.IsTrue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal X509Extensions Extensions => req.Extensions;
|
||||
|
||||
public virtual bool HasExtensions => extensions != null;
|
||||
|
||||
public TimeStampRequest(TimeStampReq req)
|
||||
{
|
||||
this.req = req;
|
||||
extensions = req.Extensions;
|
||||
}
|
||||
|
||||
public TimeStampRequest(byte[] req)
|
||||
: this(new Asn1InputStream(req))
|
||||
{
|
||||
}
|
||||
|
||||
public TimeStampRequest(Stream input)
|
||||
: this(new Asn1InputStream(input))
|
||||
{
|
||||
}
|
||||
|
||||
private TimeStampRequest(Asn1InputStream str)
|
||||
{
|
||||
try
|
||||
{
|
||||
req = TimeStampReq.GetInstance(str.ReadObject());
|
||||
}
|
||||
catch (InvalidCastException ex)
|
||||
{
|
||||
throw new IOException("malformed request: " + ex);
|
||||
}
|
||||
catch (ArgumentException ex2)
|
||||
{
|
||||
throw new IOException("malformed request: " + ex2);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetMessageImprintDigest()
|
||||
{
|
||||
return req.MessageImprint.GetHashedMessage();
|
||||
}
|
||||
|
||||
public void Validate(IList algorithms, IList policies, IList extensions)
|
||||
{
|
||||
if (!algorithms.Contains(MessageImprintAlgOid))
|
||||
{
|
||||
throw new TspValidationException("request contains unknown algorithm", 128);
|
||||
}
|
||||
if (policies != null && ReqPolicy != null && !policies.Contains(ReqPolicy))
|
||||
{
|
||||
throw new TspValidationException("request contains unknown policy", 256);
|
||||
}
|
||||
if (Extensions != null && extensions != null)
|
||||
{
|
||||
foreach (DerObjectIdentifier extensionOid in Extensions.ExtensionOids)
|
||||
{
|
||||
if (!extensions.Contains(extensionOid.Id))
|
||||
{
|
||||
throw new TspValidationException("request contains unknown extension", 8388608);
|
||||
}
|
||||
}
|
||||
}
|
||||
int digestLength = TspUtil.GetDigestLength(MessageImprintAlgOid);
|
||||
if (digestLength != GetMessageImprintDigest().Length)
|
||||
{
|
||||
throw new TspValidationException("imprint digest the wrong length", 4);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
return req.GetEncoded();
|
||||
}
|
||||
|
||||
public virtual X509Extension GetExtension(DerObjectIdentifier oid)
|
||||
{
|
||||
if (extensions != null)
|
||||
{
|
||||
return extensions.GetExtension(oid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual IList GetExtensionOids()
|
||||
{
|
||||
return TspUtil.GetExtensionOids(extensions);
|
||||
}
|
||||
|
||||
protected override X509Extensions GetX509Extensions()
|
||||
{
|
||||
return Extensions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Tsp;
|
||||
using Org.BouncyCastle.Asn1.X509;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public class TimeStampRequestGenerator
|
||||
{
|
||||
private DerObjectIdentifier reqPolicy;
|
||||
|
||||
private DerBoolean certReq;
|
||||
|
||||
private IDictionary extensions = Platform.CreateHashtable();
|
||||
|
||||
private IList extOrdering = Platform.CreateArrayList();
|
||||
|
||||
public void SetReqPolicy(string reqPolicy)
|
||||
{
|
||||
this.reqPolicy = new DerObjectIdentifier(reqPolicy);
|
||||
}
|
||||
|
||||
public void SetCertReq(bool certReq)
|
||||
{
|
||||
this.certReq = DerBoolean.GetInstance(certReq);
|
||||
}
|
||||
|
||||
[Obsolete("Use method taking DerObjectIdentifier")]
|
||||
public void AddExtension(string oid, bool critical, Asn1Encodable value)
|
||||
{
|
||||
AddExtension(oid, critical, value.GetEncoded());
|
||||
}
|
||||
|
||||
[Obsolete("Use method taking DerObjectIdentifier")]
|
||||
public void AddExtension(string oid, bool critical, byte[] value)
|
||||
{
|
||||
DerObjectIdentifier derObjectIdentifier = new DerObjectIdentifier(oid);
|
||||
extensions[derObjectIdentifier] = new X509Extension(critical, new DerOctetString(value));
|
||||
extOrdering.Add(derObjectIdentifier);
|
||||
}
|
||||
|
||||
public virtual void AddExtension(DerObjectIdentifier oid, bool critical, Asn1Encodable extValue)
|
||||
{
|
||||
AddExtension(oid, critical, extValue.GetEncoded());
|
||||
}
|
||||
|
||||
public virtual void AddExtension(DerObjectIdentifier oid, bool critical, byte[] extValue)
|
||||
{
|
||||
extensions.Add(oid, new X509Extension(critical, new DerOctetString(extValue)));
|
||||
extOrdering.Add(oid);
|
||||
}
|
||||
|
||||
public TimeStampRequest Generate(string digestAlgorithm, byte[] digest)
|
||||
{
|
||||
return Generate(digestAlgorithm, digest, null);
|
||||
}
|
||||
|
||||
public TimeStampRequest Generate(string digestAlgorithmOid, byte[] digest, BigInteger nonce)
|
||||
{
|
||||
if (digestAlgorithmOid == null)
|
||||
{
|
||||
throw new ArgumentException("No digest algorithm specified");
|
||||
}
|
||||
DerObjectIdentifier algorithm = new DerObjectIdentifier(digestAlgorithmOid);
|
||||
AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(algorithm, DerNull.Instance);
|
||||
MessageImprint messageImprint = new MessageImprint(hashAlgorithm, digest);
|
||||
X509Extensions x509Extensions = null;
|
||||
if (extOrdering.Count != 0)
|
||||
{
|
||||
x509Extensions = new X509Extensions(extOrdering, extensions);
|
||||
}
|
||||
DerInteger nonce2 = ((nonce == null) ? null : new DerInteger(nonce));
|
||||
return new TimeStampRequest(new TimeStampReq(messageImprint, reqPolicy, nonce2, certReq, x509Extensions));
|
||||
}
|
||||
|
||||
public virtual TimeStampRequest Generate(DerObjectIdentifier digestAlgorithm, byte[] digest)
|
||||
{
|
||||
return Generate(digestAlgorithm.Id, digest);
|
||||
}
|
||||
|
||||
public virtual TimeStampRequest Generate(DerObjectIdentifier digestAlgorithm, byte[] digest, BigInteger nonce)
|
||||
{
|
||||
return Generate(digestAlgorithm.Id, digest, nonce);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Cmp;
|
||||
using Org.BouncyCastle.Asn1.Cms;
|
||||
using Org.BouncyCastle.Asn1.Pkcs;
|
||||
using Org.BouncyCastle.Asn1.Tsp;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public class TimeStampResponse
|
||||
{
|
||||
private TimeStampResp resp;
|
||||
|
||||
private TimeStampToken timeStampToken;
|
||||
|
||||
public int Status => resp.Status.Status.IntValue;
|
||||
|
||||
public TimeStampToken TimeStampToken => timeStampToken;
|
||||
|
||||
public TimeStampResponse(TimeStampResp resp)
|
||||
{
|
||||
this.resp = resp;
|
||||
if (resp.TimeStampToken != null)
|
||||
{
|
||||
timeStampToken = new TimeStampToken(resp.TimeStampToken);
|
||||
}
|
||||
}
|
||||
|
||||
public TimeStampResponse(byte[] resp)
|
||||
: this(readTimeStampResp(new Asn1InputStream(resp)))
|
||||
{
|
||||
}
|
||||
|
||||
public TimeStampResponse(Stream input)
|
||||
: this(readTimeStampResp(new Asn1InputStream(input)))
|
||||
{
|
||||
}
|
||||
|
||||
private static TimeStampResp readTimeStampResp(Asn1InputStream input)
|
||||
{
|
||||
try
|
||||
{
|
||||
return TimeStampResp.GetInstance(input.ReadObject());
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
throw new TspException("malformed timestamp response: " + ex, ex);
|
||||
}
|
||||
catch (InvalidCastException ex2)
|
||||
{
|
||||
throw new TspException("malformed timestamp response: " + ex2, ex2);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetStatusString()
|
||||
{
|
||||
if (resp.Status.StatusString == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
PkiFreeText statusString = resp.Status.StatusString;
|
||||
for (int i = 0; i != statusString.Count; i++)
|
||||
{
|
||||
stringBuilder.Append(statusString[i].GetString());
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public PkiFailureInfo GetFailInfo()
|
||||
{
|
||||
if (resp.Status.FailInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new PkiFailureInfo(resp.Status.FailInfo);
|
||||
}
|
||||
|
||||
public void Validate(TimeStampRequest request)
|
||||
{
|
||||
TimeStampToken timeStampToken = TimeStampToken;
|
||||
if (timeStampToken != null)
|
||||
{
|
||||
TimeStampTokenInfo timeStampInfo = timeStampToken.TimeStampInfo;
|
||||
if (request.Nonce != null && !request.Nonce.Equals(timeStampInfo.Nonce))
|
||||
{
|
||||
throw new TspValidationException("response contains wrong nonce value.");
|
||||
}
|
||||
if (Status != 0 && Status != 1)
|
||||
{
|
||||
throw new TspValidationException("time stamp token found in failed request.");
|
||||
}
|
||||
if (!Arrays.ConstantTimeAreEqual(request.GetMessageImprintDigest(), timeStampInfo.GetMessageImprintDigest()))
|
||||
{
|
||||
throw new TspValidationException("response for different message imprint digest.");
|
||||
}
|
||||
if (!timeStampInfo.MessageImprintAlgOid.Equals(request.MessageImprintAlgOid))
|
||||
{
|
||||
throw new TspValidationException("response for different message imprint algorithm.");
|
||||
}
|
||||
Org.BouncyCastle.Asn1.Cms.Attribute attribute = timeStampToken.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificate];
|
||||
Org.BouncyCastle.Asn1.Cms.Attribute attribute2 = timeStampToken.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2];
|
||||
if (attribute == null && attribute2 == null)
|
||||
{
|
||||
throw new TspValidationException("no signing certificate attribute present.");
|
||||
}
|
||||
if (attribute != null)
|
||||
{
|
||||
}
|
||||
if (request.ReqPolicy != null && !request.ReqPolicy.Equals(timeStampInfo.Policy))
|
||||
{
|
||||
throw new TspValidationException("TSA policy wrong for request.");
|
||||
}
|
||||
}
|
||||
else if (Status == 0 || Status == 1)
|
||||
{
|
||||
throw new TspValidationException("no time stamp token found and one expected.");
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
return resp.GetEncoded();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Cmp;
|
||||
using Org.BouncyCastle.Asn1.Cms;
|
||||
using Org.BouncyCastle.Asn1.Tsp;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public class TimeStampResponseGenerator
|
||||
{
|
||||
private class FailInfo : DerBitString
|
||||
{
|
||||
internal FailInfo(int failInfoValue)
|
||||
: base(failInfoValue)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private PkiStatus status;
|
||||
|
||||
private Asn1EncodableVector statusStrings;
|
||||
|
||||
private int failInfo;
|
||||
|
||||
private TimeStampTokenGenerator tokenGenerator;
|
||||
|
||||
private IList acceptedAlgorithms;
|
||||
|
||||
private IList acceptedPolicies;
|
||||
|
||||
private IList acceptedExtensions;
|
||||
|
||||
public TimeStampResponseGenerator(TimeStampTokenGenerator tokenGenerator, IList acceptedAlgorithms)
|
||||
: this(tokenGenerator, acceptedAlgorithms, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public TimeStampResponseGenerator(TimeStampTokenGenerator tokenGenerator, IList acceptedAlgorithms, IList acceptedPolicy)
|
||||
: this(tokenGenerator, acceptedAlgorithms, acceptedPolicy, null)
|
||||
{
|
||||
}
|
||||
|
||||
public TimeStampResponseGenerator(TimeStampTokenGenerator tokenGenerator, IList acceptedAlgorithms, IList acceptedPolicies, IList acceptedExtensions)
|
||||
{
|
||||
this.tokenGenerator = tokenGenerator;
|
||||
this.acceptedAlgorithms = acceptedAlgorithms;
|
||||
this.acceptedPolicies = acceptedPolicies;
|
||||
this.acceptedExtensions = acceptedExtensions;
|
||||
statusStrings = new Asn1EncodableVector();
|
||||
}
|
||||
|
||||
private void AddStatusString(string statusString)
|
||||
{
|
||||
statusStrings.Add(new DerUtf8String(statusString));
|
||||
}
|
||||
|
||||
private void SetFailInfoField(int field)
|
||||
{
|
||||
failInfo |= field;
|
||||
}
|
||||
|
||||
private PkiStatusInfo GetPkiStatusInfo()
|
||||
{
|
||||
Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector(new DerInteger((int)status));
|
||||
if (statusStrings.Count > 0)
|
||||
{
|
||||
asn1EncodableVector.Add(new PkiFreeText(new DerSequence(statusStrings)));
|
||||
}
|
||||
if (failInfo != 0)
|
||||
{
|
||||
asn1EncodableVector.Add(new FailInfo(failInfo));
|
||||
}
|
||||
return new PkiStatusInfo(new DerSequence(asn1EncodableVector));
|
||||
}
|
||||
|
||||
public TimeStampResponse Generate(TimeStampRequest request, BigInteger serialNumber, DateTime genTime)
|
||||
{
|
||||
return Generate(request, serialNumber, new DateTimeObject(genTime));
|
||||
}
|
||||
|
||||
public TimeStampResponse Generate(TimeStampRequest request, BigInteger serialNumber, DateTimeObject genTime)
|
||||
{
|
||||
TimeStampResp resp;
|
||||
try
|
||||
{
|
||||
if (genTime == null)
|
||||
{
|
||||
throw new TspValidationException("The time source is not available.", 512);
|
||||
}
|
||||
request.Validate(acceptedAlgorithms, acceptedPolicies, acceptedExtensions);
|
||||
status = PkiStatus.Granted;
|
||||
AddStatusString("Operation Okay");
|
||||
PkiStatusInfo pkiStatusInfo = GetPkiStatusInfo();
|
||||
ContentInfo instance;
|
||||
try
|
||||
{
|
||||
TimeStampToken timeStampToken = tokenGenerator.Generate(request, serialNumber, genTime.Value);
|
||||
byte[] encoded = timeStampToken.ToCmsSignedData().GetEncoded();
|
||||
instance = ContentInfo.GetInstance(Asn1Object.FromByteArray(encoded));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new TspException("Timestamp token received cannot be converted to ContentInfo", e);
|
||||
}
|
||||
resp = new TimeStampResp(pkiStatusInfo, instance);
|
||||
}
|
||||
catch (TspValidationException ex)
|
||||
{
|
||||
status = PkiStatus.Rejection;
|
||||
SetFailInfoField(ex.FailureCode);
|
||||
AddStatusString(ex.Message);
|
||||
PkiStatusInfo pkiStatusInfo2 = GetPkiStatusInfo();
|
||||
resp = new TimeStampResp(pkiStatusInfo2, null);
|
||||
}
|
||||
try
|
||||
{
|
||||
return new TimeStampResponse(resp);
|
||||
}
|
||||
catch (IOException e2)
|
||||
{
|
||||
throw new TspException("created badly formatted response!", e2);
|
||||
}
|
||||
}
|
||||
|
||||
public TimeStampResponse GenerateFailResponse(PkiStatus status, int failInfoField, string statusString)
|
||||
{
|
||||
this.status = status;
|
||||
SetFailInfoField(failInfoField);
|
||||
if (statusString != null)
|
||||
{
|
||||
AddStatusString(statusString);
|
||||
}
|
||||
PkiStatusInfo pkiStatusInfo = GetPkiStatusInfo();
|
||||
TimeStampResp resp = new TimeStampResp(pkiStatusInfo, null);
|
||||
try
|
||||
{
|
||||
return new TimeStampResponse(resp);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new TspException("created badly formatted response!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Cms;
|
||||
using Org.BouncyCastle.Asn1.Ess;
|
||||
using Org.BouncyCastle.Asn1.Nist;
|
||||
using Org.BouncyCastle.Asn1.Oiw;
|
||||
using Org.BouncyCastle.Asn1.Pkcs;
|
||||
using Org.BouncyCastle.Asn1.Tsp;
|
||||
using Org.BouncyCastle.Asn1.X509;
|
||||
using Org.BouncyCastle.Cms;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Security.Certificates;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.X509;
|
||||
using Org.BouncyCastle.X509.Store;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public class TimeStampToken
|
||||
{
|
||||
private class CertID
|
||||
{
|
||||
private EssCertID certID;
|
||||
|
||||
private EssCertIDv2 certIDv2;
|
||||
|
||||
public IssuerSerial IssuerSerial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (certID == null)
|
||||
{
|
||||
return certIDv2.IssuerSerial;
|
||||
}
|
||||
return certID.IssuerSerial;
|
||||
}
|
||||
}
|
||||
|
||||
internal CertID(EssCertID certID)
|
||||
{
|
||||
this.certID = certID;
|
||||
certIDv2 = null;
|
||||
}
|
||||
|
||||
internal CertID(EssCertIDv2 certID)
|
||||
{
|
||||
certIDv2 = certID;
|
||||
this.certID = null;
|
||||
}
|
||||
|
||||
public string GetHashAlgorithmName()
|
||||
{
|
||||
if (certID != null)
|
||||
{
|
||||
return "SHA-1";
|
||||
}
|
||||
if (NistObjectIdentifiers.IdSha256.Equals(certIDv2.HashAlgorithm.Algorithm))
|
||||
{
|
||||
return "SHA-256";
|
||||
}
|
||||
return certIDv2.HashAlgorithm.Algorithm.Id;
|
||||
}
|
||||
|
||||
public AlgorithmIdentifier GetHashAlgorithm()
|
||||
{
|
||||
if (certID == null)
|
||||
{
|
||||
return certIDv2.HashAlgorithm;
|
||||
}
|
||||
return new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1);
|
||||
}
|
||||
|
||||
public byte[] GetCertHash()
|
||||
{
|
||||
if (certID == null)
|
||||
{
|
||||
return certIDv2.GetCertHash();
|
||||
}
|
||||
return certID.GetCertHash();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly CmsSignedData tsToken;
|
||||
|
||||
private readonly SignerInformation tsaSignerInfo;
|
||||
|
||||
private readonly TimeStampTokenInfo tstInfo;
|
||||
|
||||
private readonly CertID certID;
|
||||
|
||||
public TimeStampTokenInfo TimeStampInfo => tstInfo;
|
||||
|
||||
public SignerID SignerID => tsaSignerInfo.SignerID;
|
||||
|
||||
public Org.BouncyCastle.Asn1.Cms.AttributeTable SignedAttributes => tsaSignerInfo.SignedAttributes;
|
||||
|
||||
public Org.BouncyCastle.Asn1.Cms.AttributeTable UnsignedAttributes => tsaSignerInfo.UnsignedAttributes;
|
||||
|
||||
public TimeStampToken(Org.BouncyCastle.Asn1.Cms.ContentInfo contentInfo)
|
||||
: this(new CmsSignedData(contentInfo))
|
||||
{
|
||||
}
|
||||
|
||||
public TimeStampToken(CmsSignedData signedData)
|
||||
{
|
||||
tsToken = signedData;
|
||||
if (!tsToken.SignedContentType.Equals(PkcsObjectIdentifiers.IdCTTstInfo))
|
||||
{
|
||||
throw new TspValidationException("ContentInfo object not for a time stamp.");
|
||||
}
|
||||
ICollection signers = tsToken.GetSignerInfos().GetSigners();
|
||||
if (signers.Count != 1)
|
||||
{
|
||||
throw new ArgumentException("Time-stamp token signed by " + signers.Count + " signers, but it must contain just the TSA signature.");
|
||||
}
|
||||
IEnumerator enumerator = signers.GetEnumerator();
|
||||
enumerator.MoveNext();
|
||||
tsaSignerInfo = (SignerInformation)enumerator.Current;
|
||||
try
|
||||
{
|
||||
CmsProcessable signedContent = tsToken.SignedContent;
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
signedContent.Write(memoryStream);
|
||||
tstInfo = new TimeStampTokenInfo(TstInfo.GetInstance(Asn1Object.FromByteArray(memoryStream.ToArray())));
|
||||
Org.BouncyCastle.Asn1.Cms.Attribute attribute = tsaSignerInfo.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificate];
|
||||
if (attribute != null)
|
||||
{
|
||||
SigningCertificate instance = SigningCertificate.GetInstance(attribute.AttrValues[0]);
|
||||
certID = new CertID(EssCertID.GetInstance(instance.GetCerts()[0]));
|
||||
return;
|
||||
}
|
||||
attribute = tsaSignerInfo.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2];
|
||||
if (attribute == null)
|
||||
{
|
||||
throw new TspValidationException("no signing certificate attribute found, time stamp invalid.");
|
||||
}
|
||||
SigningCertificateV2 instance2 = SigningCertificateV2.GetInstance(attribute.AttrValues[0]);
|
||||
certID = new CertID(EssCertIDv2.GetInstance(instance2.GetCerts()[0]));
|
||||
}
|
||||
catch (CmsException ex)
|
||||
{
|
||||
throw new TspException(ex.Message, ex.InnerException);
|
||||
}
|
||||
}
|
||||
|
||||
public IX509Store GetCertificates(string type)
|
||||
{
|
||||
return tsToken.GetCertificates(type);
|
||||
}
|
||||
|
||||
public IX509Store GetCrls(string type)
|
||||
{
|
||||
return tsToken.GetCrls(type);
|
||||
}
|
||||
|
||||
public IX509Store GetAttributeCertificates(string type)
|
||||
{
|
||||
return tsToken.GetAttributeCertificates(type);
|
||||
}
|
||||
|
||||
public void Validate(X509Certificate cert)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] b = DigestUtilities.CalculateDigest(certID.GetHashAlgorithmName(), cert.GetEncoded());
|
||||
if (!Arrays.ConstantTimeAreEqual(certID.GetCertHash(), b))
|
||||
{
|
||||
throw new TspValidationException("certificate hash does not match certID hash.");
|
||||
}
|
||||
if (certID.IssuerSerial != null)
|
||||
{
|
||||
if (!certID.IssuerSerial.Serial.Value.Equals(cert.SerialNumber))
|
||||
{
|
||||
throw new TspValidationException("certificate serial number does not match certID for signature.");
|
||||
}
|
||||
GeneralName[] names = certID.IssuerSerial.Issuer.GetNames();
|
||||
X509Name issuerX509Principal = PrincipalUtilities.GetIssuerX509Principal(cert);
|
||||
bool flag = false;
|
||||
for (int i = 0; i != names.Length; i++)
|
||||
{
|
||||
if (names[i].TagNo == 4 && X509Name.GetInstance(names[i].Name).Equivalent(issuerX509Principal))
|
||||
{
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
throw new TspValidationException("certificate name does not match certID for signature. ");
|
||||
}
|
||||
}
|
||||
TspUtil.ValidateCertificate(cert);
|
||||
cert.CheckValidity(tstInfo.GenTime);
|
||||
if (!tsaSignerInfo.Verify(cert))
|
||||
{
|
||||
throw new TspValidationException("signature not created by certificate.");
|
||||
}
|
||||
}
|
||||
catch (CmsException ex)
|
||||
{
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
throw new TspException(ex.Message, ex.InnerException);
|
||||
}
|
||||
throw new TspException("CMS exception: " + ex, ex);
|
||||
}
|
||||
catch (CertificateEncodingException ex2)
|
||||
{
|
||||
throw new TspException("problem processing certificate: " + ex2, ex2);
|
||||
}
|
||||
catch (SecurityUtilityException ex3)
|
||||
{
|
||||
throw new TspException("cannot find algorithm: " + ex3.Message, ex3);
|
||||
}
|
||||
}
|
||||
|
||||
public CmsSignedData ToCmsSignedData()
|
||||
{
|
||||
return tsToken;
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
return tsToken.GetEncoded();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Cms;
|
||||
using Org.BouncyCastle.Asn1.Ess;
|
||||
using Org.BouncyCastle.Asn1.Pkcs;
|
||||
using Org.BouncyCastle.Asn1.Tsp;
|
||||
using Org.BouncyCastle.Asn1.X509;
|
||||
using Org.BouncyCastle.Cms;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Security.Certificates;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.X509;
|
||||
using Org.BouncyCastle.X509.Store;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public class TimeStampTokenGenerator
|
||||
{
|
||||
private int accuracySeconds = -1;
|
||||
|
||||
private int accuracyMillis = -1;
|
||||
|
||||
private int accuracyMicros = -1;
|
||||
|
||||
private bool ordering = false;
|
||||
|
||||
private GeneralName tsa = null;
|
||||
|
||||
private string tsaPolicyOID;
|
||||
|
||||
private AsymmetricKeyParameter key;
|
||||
|
||||
private X509Certificate cert;
|
||||
|
||||
private string digestOID;
|
||||
|
||||
private Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr;
|
||||
|
||||
private Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr;
|
||||
|
||||
private IX509Store x509Certs;
|
||||
|
||||
private IX509Store x509Crls;
|
||||
|
||||
public TimeStampTokenGenerator(AsymmetricKeyParameter key, X509Certificate cert, string digestOID, string tsaPolicyOID)
|
||||
: this(key, cert, digestOID, tsaPolicyOID, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public TimeStampTokenGenerator(AsymmetricKeyParameter key, X509Certificate cert, string digestOID, string tsaPolicyOID, Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr)
|
||||
{
|
||||
this.key = key;
|
||||
this.cert = cert;
|
||||
this.digestOID = digestOID;
|
||||
this.tsaPolicyOID = tsaPolicyOID;
|
||||
this.unsignedAttr = unsignedAttr;
|
||||
TspUtil.ValidateCertificate(cert);
|
||||
IDictionary dictionary = ((signedAttr == null) ? Platform.CreateHashtable() : signedAttr.ToDictionary());
|
||||
try
|
||||
{
|
||||
byte[] hash = DigestUtilities.CalculateDigest("SHA-1", cert.GetEncoded());
|
||||
EssCertID essCertID = new EssCertID(hash);
|
||||
Org.BouncyCastle.Asn1.Cms.Attribute attribute = new Org.BouncyCastle.Asn1.Cms.Attribute(PkcsObjectIdentifiers.IdAASigningCertificate, new DerSet(new SigningCertificate(essCertID)));
|
||||
dictionary[attribute.AttrType] = attribute;
|
||||
}
|
||||
catch (CertificateEncodingException e)
|
||||
{
|
||||
throw new TspException("Exception processing certificate.", e);
|
||||
}
|
||||
catch (SecurityUtilityException e2)
|
||||
{
|
||||
throw new TspException("Can't find a SHA-1 implementation.", e2);
|
||||
}
|
||||
this.signedAttr = new Org.BouncyCastle.Asn1.Cms.AttributeTable(dictionary);
|
||||
}
|
||||
|
||||
public void SetCertificates(IX509Store certificates)
|
||||
{
|
||||
x509Certs = certificates;
|
||||
}
|
||||
|
||||
public void SetCrls(IX509Store crls)
|
||||
{
|
||||
x509Crls = crls;
|
||||
}
|
||||
|
||||
public void SetAccuracySeconds(int accuracySeconds)
|
||||
{
|
||||
this.accuracySeconds = accuracySeconds;
|
||||
}
|
||||
|
||||
public void SetAccuracyMillis(int accuracyMillis)
|
||||
{
|
||||
this.accuracyMillis = accuracyMillis;
|
||||
}
|
||||
|
||||
public void SetAccuracyMicros(int accuracyMicros)
|
||||
{
|
||||
this.accuracyMicros = accuracyMicros;
|
||||
}
|
||||
|
||||
public void SetOrdering(bool ordering)
|
||||
{
|
||||
this.ordering = ordering;
|
||||
}
|
||||
|
||||
public void SetTsa(GeneralName tsa)
|
||||
{
|
||||
this.tsa = tsa;
|
||||
}
|
||||
|
||||
public TimeStampToken Generate(TimeStampRequest request, BigInteger serialNumber, DateTime genTime)
|
||||
{
|
||||
DerObjectIdentifier algorithm = new DerObjectIdentifier(request.MessageImprintAlgOid);
|
||||
AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(algorithm, DerNull.Instance);
|
||||
MessageImprint messageImprint = new MessageImprint(hashAlgorithm, request.GetMessageImprintDigest());
|
||||
Accuracy accuracy = null;
|
||||
if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0)
|
||||
{
|
||||
DerInteger seconds = null;
|
||||
if (accuracySeconds > 0)
|
||||
{
|
||||
seconds = new DerInteger(accuracySeconds);
|
||||
}
|
||||
DerInteger millis = null;
|
||||
if (accuracyMillis > 0)
|
||||
{
|
||||
millis = new DerInteger(accuracyMillis);
|
||||
}
|
||||
DerInteger micros = null;
|
||||
if (accuracyMicros > 0)
|
||||
{
|
||||
micros = new DerInteger(accuracyMicros);
|
||||
}
|
||||
accuracy = new Accuracy(seconds, millis, micros);
|
||||
}
|
||||
DerBoolean derBoolean = null;
|
||||
if (ordering)
|
||||
{
|
||||
derBoolean = DerBoolean.GetInstance(ordering);
|
||||
}
|
||||
DerInteger nonce = null;
|
||||
if (request.Nonce != null)
|
||||
{
|
||||
nonce = new DerInteger(request.Nonce);
|
||||
}
|
||||
DerObjectIdentifier tsaPolicyId = new DerObjectIdentifier(tsaPolicyOID);
|
||||
if (request.ReqPolicy != null)
|
||||
{
|
||||
tsaPolicyId = new DerObjectIdentifier(request.ReqPolicy);
|
||||
}
|
||||
TstInfo tstInfo = new TstInfo(tsaPolicyId, messageImprint, new DerInteger(serialNumber), new DerGeneralizedTime(genTime), accuracy, derBoolean, nonce, tsa, request.Extensions);
|
||||
try
|
||||
{
|
||||
CmsSignedDataGenerator cmsSignedDataGenerator = new CmsSignedDataGenerator();
|
||||
byte[] derEncoded = tstInfo.GetDerEncoded();
|
||||
if (request.CertReq)
|
||||
{
|
||||
cmsSignedDataGenerator.AddCertificates(x509Certs);
|
||||
}
|
||||
cmsSignedDataGenerator.AddCrls(x509Crls);
|
||||
cmsSignedDataGenerator.AddSigner(key, cert, digestOID, signedAttr, unsignedAttr);
|
||||
CmsSignedData signedData = cmsSignedDataGenerator.Generate(PkcsObjectIdentifiers.IdCTTstInfo.Id, new CmsProcessableByteArray(derEncoded), encapsulate: true);
|
||||
return new TimeStampToken(signedData);
|
||||
}
|
||||
catch (CmsException e)
|
||||
{
|
||||
throw new TspException("Error generating time-stamp token", e);
|
||||
}
|
||||
catch (IOException e2)
|
||||
{
|
||||
throw new TspException("Exception encoding info", e2);
|
||||
}
|
||||
catch (X509StoreException e3)
|
||||
{
|
||||
throw new TspException("Exception handling CertStore", e3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Asn1.Tsp;
|
||||
using Org.BouncyCastle.Asn1.X509;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public class TimeStampTokenInfo
|
||||
{
|
||||
private TstInfo tstInfo;
|
||||
|
||||
private DateTime genTime;
|
||||
|
||||
public bool IsOrdered => tstInfo.Ordering.IsTrue;
|
||||
|
||||
public Accuracy Accuracy => tstInfo.Accuracy;
|
||||
|
||||
public DateTime GenTime => genTime;
|
||||
|
||||
public GenTimeAccuracy GenTimeAccuracy
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Accuracy != null)
|
||||
{
|
||||
return new GenTimeAccuracy(Accuracy);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Policy => tstInfo.Policy.Id;
|
||||
|
||||
public BigInteger SerialNumber => tstInfo.SerialNumber.Value;
|
||||
|
||||
public GeneralName Tsa => tstInfo.Tsa;
|
||||
|
||||
public BigInteger Nonce
|
||||
{
|
||||
get
|
||||
{
|
||||
if (tstInfo.Nonce != null)
|
||||
{
|
||||
return tstInfo.Nonce.Value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public AlgorithmIdentifier HashAlgorithm => tstInfo.MessageImprint.HashAlgorithm;
|
||||
|
||||
public string MessageImprintAlgOid => tstInfo.MessageImprint.HashAlgorithm.Algorithm.Id;
|
||||
|
||||
public TstInfo TstInfo => tstInfo;
|
||||
|
||||
public TimeStampTokenInfo(TstInfo tstInfo)
|
||||
{
|
||||
this.tstInfo = tstInfo;
|
||||
try
|
||||
{
|
||||
genTime = tstInfo.GenTime.ToDateTime();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new TspException("unable to parse genTime field: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetMessageImprintDigest()
|
||||
{
|
||||
return tstInfo.MessageImprint.GetHashedMessage();
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
return tstInfo.GetEncoded();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Asn1.CryptoPro;
|
||||
using Org.BouncyCastle.Asn1.GM;
|
||||
using Org.BouncyCastle.Asn1.Nist;
|
||||
using Org.BouncyCastle.Asn1.Oiw;
|
||||
using Org.BouncyCastle.Asn1.Pkcs;
|
||||
using Org.BouncyCastle.Asn1.Rosstandart;
|
||||
using Org.BouncyCastle.Asn1.TeleTrust;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public abstract class TspAlgorithms
|
||||
{
|
||||
public static readonly string MD5;
|
||||
|
||||
public static readonly string Sha1;
|
||||
|
||||
public static readonly string Sha224;
|
||||
|
||||
public static readonly string Sha256;
|
||||
|
||||
public static readonly string Sha384;
|
||||
|
||||
public static readonly string Sha512;
|
||||
|
||||
public static readonly string RipeMD128;
|
||||
|
||||
public static readonly string RipeMD160;
|
||||
|
||||
public static readonly string RipeMD256;
|
||||
|
||||
public static readonly string Gost3411;
|
||||
|
||||
public static readonly string Gost3411_2012_256;
|
||||
|
||||
public static readonly string Gost3411_2012_512;
|
||||
|
||||
public static readonly string SM3;
|
||||
|
||||
public static readonly IList Allowed;
|
||||
|
||||
static TspAlgorithms()
|
||||
{
|
||||
MD5 = PkcsObjectIdentifiers.MD5.Id;
|
||||
Sha1 = OiwObjectIdentifiers.IdSha1.Id;
|
||||
Sha224 = NistObjectIdentifiers.IdSha224.Id;
|
||||
Sha256 = NistObjectIdentifiers.IdSha256.Id;
|
||||
Sha384 = NistObjectIdentifiers.IdSha384.Id;
|
||||
Sha512 = NistObjectIdentifiers.IdSha512.Id;
|
||||
RipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id;
|
||||
RipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id;
|
||||
RipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id;
|
||||
Gost3411 = CryptoProObjectIdentifiers.GostR3411.Id;
|
||||
Gost3411_2012_256 = RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id;
|
||||
Gost3411_2012_512 = RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id;
|
||||
SM3 = GMObjectIdentifiers.sm3.Id;
|
||||
string[] array = new string[13]
|
||||
{
|
||||
Gost3411, Gost3411_2012_256, Gost3411_2012_512, MD5, RipeMD128, RipeMD160, RipeMD256, Sha1, Sha224, Sha256,
|
||||
Sha384, Sha512, SM3
|
||||
};
|
||||
Allowed = Platform.CreateArrayList();
|
||||
string[] array2 = array;
|
||||
foreach (string value in array2)
|
||||
{
|
||||
Allowed.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
[Serializable]
|
||||
public class TspException : Exception
|
||||
{
|
||||
public TspException()
|
||||
{
|
||||
}
|
||||
|
||||
public TspException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public TspException(string message, Exception e)
|
||||
: base(message, e)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Cms;
|
||||
using Org.BouncyCastle.Asn1.CryptoPro;
|
||||
using Org.BouncyCastle.Asn1.GM;
|
||||
using Org.BouncyCastle.Asn1.Nist;
|
||||
using Org.BouncyCastle.Asn1.Oiw;
|
||||
using Org.BouncyCastle.Asn1.Pkcs;
|
||||
using Org.BouncyCastle.Asn1.Rosstandart;
|
||||
using Org.BouncyCastle.Asn1.TeleTrust;
|
||||
using Org.BouncyCastle.Asn1.X509;
|
||||
using Org.BouncyCastle.Cms;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
using Org.BouncyCastle.X509;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
public class TspUtil
|
||||
{
|
||||
private static ISet EmptySet;
|
||||
|
||||
private static IList EmptyList;
|
||||
|
||||
private static readonly IDictionary digestLengths;
|
||||
|
||||
private static readonly IDictionary digestNames;
|
||||
|
||||
static TspUtil()
|
||||
{
|
||||
EmptySet = CollectionUtilities.ReadOnly(new HashSet());
|
||||
EmptyList = CollectionUtilities.ReadOnly(Platform.CreateArrayList());
|
||||
digestLengths = Platform.CreateHashtable();
|
||||
digestNames = Platform.CreateHashtable();
|
||||
digestLengths.Add(PkcsObjectIdentifiers.MD5.Id, 16);
|
||||
digestLengths.Add(OiwObjectIdentifiers.IdSha1.Id, 20);
|
||||
digestLengths.Add(NistObjectIdentifiers.IdSha224.Id, 28);
|
||||
digestLengths.Add(NistObjectIdentifiers.IdSha256.Id, 32);
|
||||
digestLengths.Add(NistObjectIdentifiers.IdSha384.Id, 48);
|
||||
digestLengths.Add(NistObjectIdentifiers.IdSha512.Id, 64);
|
||||
digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, 16);
|
||||
digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, 20);
|
||||
digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, 32);
|
||||
digestLengths.Add(CryptoProObjectIdentifiers.GostR3411.Id, 32);
|
||||
digestLengths.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id, 32);
|
||||
digestLengths.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id, 64);
|
||||
digestLengths.Add(GMObjectIdentifiers.sm3.Id, 32);
|
||||
digestNames.Add(PkcsObjectIdentifiers.MD5.Id, "MD5");
|
||||
digestNames.Add(OiwObjectIdentifiers.IdSha1.Id, "SHA1");
|
||||
digestNames.Add(NistObjectIdentifiers.IdSha224.Id, "SHA224");
|
||||
digestNames.Add(NistObjectIdentifiers.IdSha256.Id, "SHA256");
|
||||
digestNames.Add(NistObjectIdentifiers.IdSha384.Id, "SHA384");
|
||||
digestNames.Add(NistObjectIdentifiers.IdSha512.Id, "SHA512");
|
||||
digestNames.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption.Id, "MD5");
|
||||
digestNames.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id, "SHA1");
|
||||
digestNames.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id, "SHA224");
|
||||
digestNames.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id, "SHA256");
|
||||
digestNames.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption.Id, "SHA384");
|
||||
digestNames.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id, "SHA512");
|
||||
digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, "RIPEMD128");
|
||||
digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, "RIPEMD160");
|
||||
digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256");
|
||||
digestNames.Add(CryptoProObjectIdentifiers.GostR3411.Id, "GOST3411");
|
||||
digestNames.Add(OiwObjectIdentifiers.DsaWithSha1.Id, "SHA1");
|
||||
digestNames.Add(OiwObjectIdentifiers.Sha1WithRsa.Id, "SHA1");
|
||||
digestNames.Add(OiwObjectIdentifiers.MD5WithRsa.Id, "MD5");
|
||||
digestNames.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id, "GOST3411-2012-256");
|
||||
digestNames.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id, "GOST3411-2012-512");
|
||||
digestNames.Add(GMObjectIdentifiers.sm3.Id, "SM3");
|
||||
}
|
||||
|
||||
public static ICollection GetSignatureTimestamps(SignerInformation signerInfo)
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttributes = signerInfo.UnsignedAttributes;
|
||||
if (unsignedAttributes != null)
|
||||
{
|
||||
foreach (Org.BouncyCastle.Asn1.Cms.Attribute item in unsignedAttributes.GetAll(PkcsObjectIdentifiers.IdAASignatureTimeStampToken))
|
||||
{
|
||||
foreach (Asn1Encodable attrValue in item.AttrValues)
|
||||
{
|
||||
try
|
||||
{
|
||||
Org.BouncyCastle.Asn1.Cms.ContentInfo instance = Org.BouncyCastle.Asn1.Cms.ContentInfo.GetInstance(attrValue.ToAsn1Object());
|
||||
TimeStampToken timeStampToken = new TimeStampToken(instance);
|
||||
TimeStampTokenInfo timeStampInfo = timeStampToken.TimeStampInfo;
|
||||
byte[] a = DigestUtilities.CalculateDigest(GetDigestAlgName(timeStampInfo.MessageImprintAlgOid), signerInfo.GetSignature());
|
||||
if (!Arrays.ConstantTimeAreEqual(a, timeStampInfo.GetMessageImprintDigest()))
|
||||
{
|
||||
throw new TspValidationException("Incorrect digest in message imprint");
|
||||
}
|
||||
list.Add(timeStampToken);
|
||||
}
|
||||
catch (SecurityUtilityException)
|
||||
{
|
||||
throw new TspValidationException("Unknown hash algorithm specified in timestamp");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new TspValidationException("Timestamp could not be parsed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void ValidateCertificate(X509Certificate cert)
|
||||
{
|
||||
if (cert.Version != 3)
|
||||
{
|
||||
throw new ArgumentException("Certificate must have an ExtendedKeyUsage extension.");
|
||||
}
|
||||
Asn1OctetString extensionValue = cert.GetExtensionValue(X509Extensions.ExtendedKeyUsage);
|
||||
if (extensionValue == null)
|
||||
{
|
||||
throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension.");
|
||||
}
|
||||
if (!cert.GetCriticalExtensionOids().Contains(X509Extensions.ExtendedKeyUsage.Id))
|
||||
{
|
||||
throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension marked as critical.");
|
||||
}
|
||||
try
|
||||
{
|
||||
ExtendedKeyUsage instance = ExtendedKeyUsage.GetInstance(Asn1Object.FromByteArray(extensionValue.GetOctets()));
|
||||
if (!instance.HasKeyPurposeId(KeyPurposeID.IdKPTimeStamping) || instance.Count != 1)
|
||||
{
|
||||
throw new TspValidationException("ExtendedKeyUsage not solely time stamping.");
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
throw new TspValidationException("cannot process ExtendedKeyUsage extension");
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetDigestAlgName(string digestAlgOID)
|
||||
{
|
||||
string text = (string)digestNames[digestAlgOID];
|
||||
if (text == null)
|
||||
{
|
||||
return digestAlgOID;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
internal static int GetDigestLength(string digestAlgOID)
|
||||
{
|
||||
if (!digestLengths.Contains(digestAlgOID))
|
||||
{
|
||||
throw new TspException("digest algorithm cannot be found.");
|
||||
}
|
||||
return (int)digestLengths[digestAlgOID];
|
||||
}
|
||||
|
||||
internal static IDigest CreateDigestInstance(string digestAlgOID)
|
||||
{
|
||||
string digestAlgName = GetDigestAlgName(digestAlgOID);
|
||||
return DigestUtilities.GetDigest(digestAlgName);
|
||||
}
|
||||
|
||||
internal static ISet GetCriticalExtensionOids(X509Extensions extensions)
|
||||
{
|
||||
if (extensions == null)
|
||||
{
|
||||
return EmptySet;
|
||||
}
|
||||
return CollectionUtilities.ReadOnly(new HashSet(extensions.GetCriticalExtensionOids()));
|
||||
}
|
||||
|
||||
internal static ISet GetNonCriticalExtensionOids(X509Extensions extensions)
|
||||
{
|
||||
if (extensions == null)
|
||||
{
|
||||
return EmptySet;
|
||||
}
|
||||
return CollectionUtilities.ReadOnly(new HashSet(extensions.GetNonCriticalExtensionOids()));
|
||||
}
|
||||
|
||||
internal static IList GetExtensionOids(X509Extensions extensions)
|
||||
{
|
||||
if (extensions == null)
|
||||
{
|
||||
return EmptyList;
|
||||
}
|
||||
return CollectionUtilities.ReadOnly(Platform.CreateArrayList(extensions.GetExtensionOids()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Tsp;
|
||||
|
||||
[Serializable]
|
||||
public class TspValidationException : TspException
|
||||
{
|
||||
private int failureCode;
|
||||
|
||||
public int FailureCode => failureCode;
|
||||
|
||||
public TspValidationException(string message)
|
||||
: base(message)
|
||||
{
|
||||
failureCode = -1;
|
||||
}
|
||||
|
||||
public TspValidationException(string message, int failureCode)
|
||||
: base(message)
|
||||
{
|
||||
this.failureCode = failureCode;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user