TimeStampTokenGenerator
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Asn1.Ess;
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.Crypto;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities.Collections;
using Org.BouncyCastle.Utilities.Date;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.IO;
namespace Org.BouncyCastle.Tsp
{
public class TimeStampTokenGenerator
{
private class TableGen : CmsAttributeTableGenerator
{
private readonly SignerInfoGenerator infoGen;
private readonly EssCertID essCertID;
public TableGen(SignerInfoGenerator infoGen, EssCertID essCertID)
{
this.infoGen = infoGen;
this.essCertID = essCertID;
}
public Org.BouncyCastle.Asn1.Cms.AttributeTable GetAttributes(IDictionary<CmsAttributeTableParameter, object> parameters)
{
Org.BouncyCastle.Asn1.Cms.AttributeTable attributes = infoGen.signedGen.GetAttributes(parameters);
if (attributes[PkcsObjectIdentifiers.IdAASigningCertificate] == null)
return attributes.Add(PkcsObjectIdentifiers.IdAASigningCertificate, new SigningCertificate(essCertID));
return attributes;
}
}
private class TableGen2 : CmsAttributeTableGenerator
{
private readonly SignerInfoGenerator infoGen;
private readonly EssCertIDv2 essCertID;
public TableGen2(SignerInfoGenerator infoGen, EssCertIDv2 essCertID)
{
this.infoGen = infoGen;
this.essCertID = essCertID;
}
public Org.BouncyCastle.Asn1.Cms.AttributeTable GetAttributes(IDictionary<CmsAttributeTableParameter, object> parameters)
{
Org.BouncyCastle.Asn1.Cms.AttributeTable attributes = infoGen.signedGen.GetAttributes(parameters);
if (attributes[PkcsObjectIdentifiers.IdAASigningCertificateV2] == null)
return attributes.Add(PkcsObjectIdentifiers.IdAASigningCertificateV2, new SigningCertificateV2(essCertID));
return attributes;
}
}
private int accuracySeconds = -1;
private int accuracyMillis = -1;
private int accuracyMicros = -1;
private bool ordering;
private GeneralName tsa;
private DerObjectIdentifier tsaPolicyOID;
private IStore<X509Certificate> x509Certs;
private IStore<X509Crl> x509Crls;
private IStore<X509V2AttributeCertificate> x509AttrCerts;
private Dictionary<DerObjectIdentifier, IStore<Asn1Encodable>> otherRevoc = new Dictionary<DerObjectIdentifier, IStore<Asn1Encodable>>();
private SignerInfoGenerator signerInfoGenerator;
private Resolution resolution;
public Resolution Resolution {
get {
return resolution;
}
set {
resolution = value;
}
}
public TimeStampTokenGenerator(AsymmetricKeyParameter key, X509Certificate cert, string digestOID, string tsaPolicyOID)
: this(key, cert, digestOID, tsaPolicyOID, null, null)
{
}
public TimeStampTokenGenerator(SignerInfoGenerator signerInfoGen, IDigestFactory digestCalculator, DerObjectIdentifier tsaPolicy, bool isIssuerSerialIncluded)
{
signerInfoGenerator = signerInfoGen;
tsaPolicyOID = tsaPolicy;
X509Certificate certificate = signerInfoGen.certificate;
if (certificate == null)
throw new ArgumentException("SignerInfoGenerator must have an associated certificate");
X509Certificate x509Certificate = certificate;
TspUtil.ValidateCertificate(x509Certificate);
DerObjectIdentifier algorithm = ((AlgorithmIdentifier)digestCalculator.AlgorithmDetails).Algorithm;
try {
DerOctetString certHash = DerOctetString.WithContents(Org.BouncyCastle.X509.X509Utilities.CalculateDigest(digestCalculator, x509Certificate.GetEncoded()));
IssuerSerial issuerSerial = null;
if (isIssuerSerialIncluded)
issuerSerial = new IssuerSerial(new GeneralNames(new GeneralName(x509Certificate.IssuerDN)), x509Certificate.CertificateStructure.SerialNumber);
if (OiwObjectIdentifiers.IdSha1.Equals(algorithm)) {
EssCertID essCertID = new EssCertID(certHash, issuerSerial);
signerInfoGenerator = signerInfoGen.NewBuilder().WithSignedAttributeGenerator(new TableGen(signerInfoGen, essCertID)).Build(signerInfoGen.contentSigner, signerInfoGen.certificate);
} else {
EssCertIDv2 essCertID2 = new EssCertIDv2(new AlgorithmIdentifier(algorithm), certHash, issuerSerial);
signerInfoGenerator = signerInfoGen.NewBuilder().WithSignedAttributeGenerator(new TableGen2(signerInfoGen, essCertID2)).Build(signerInfoGen.contentSigner, signerInfoGen.certificate);
}
} catch (Exception innerException) {
throw new TspException("Exception processing certificate", innerException);
}
}
public TimeStampTokenGenerator(AsymmetricKeyParameter key, X509Certificate cert, string digestOID, string tsaPolicyOID, Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr)
: this(MakeInfoGenerator(key, cert, new DerObjectIdentifier(digestOID), signedAttr, unsignedAttr), Asn1DigestFactory.Get(OiwObjectIdentifiers.IdSha1), (tsaPolicyOID != null) ? new DerObjectIdentifier(tsaPolicyOID) : null, false)
{
}
internal static SignerInfoGenerator MakeInfoGenerator(AsymmetricKeyParameter key, X509Certificate cert, DerObjectIdentifier digestOid, Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr)
{
TspUtil.ValidateCertificate(cert);
IDictionary<DerObjectIdentifier, object> attrs = (signedAttr == null) ? new Dictionary<DerObjectIdentifier, object>() : signedAttr.ToDictionary();
string digestAlgName = CmsSignedHelper.GetDigestAlgName(digestOid);
DerObjectIdentifier encOid = CmsSignedHelper.GetEncOid(key, digestOid.Id);
Asn1SignatureFactory contentSigner = new Asn1SignatureFactory(digestAlgName + "with" + CmsSignedHelper.GetEncryptionAlgName(encOid), key);
return new SignerInfoGeneratorBuilder().WithSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new Org.BouncyCastle.Asn1.Cms.AttributeTable(attrs))).WithUnsignedAttributeGenerator(new SimpleAttributeTableGenerator(unsignedAttr)).Build(contentSigner, cert);
}
public void SetAttributeCertificates(IStore<X509V2AttributeCertificate> attributeCertificates)
{
x509AttrCerts = attributeCertificates;
}
public void SetCertificates(IStore<X509Certificate> certificates)
{
x509Certs = certificates;
}
public void SetCrls(IStore<X509Crl> crls)
{
x509Crls = crls;
}
public void AddOtherRevocationInfos(DerObjectIdentifier otherRevInfoFormat, IStore<Asn1Encodable> otherRevInfoStore)
{
otherRevoc[otherRevInfoFormat] = otherRevInfoStore;
}
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)
{
return Generate(request, serialNumber, genTime, null);
}
public TimeStampToken Generate(TimeStampRequest request, BigInteger serialNumber, DateTime genTime, X509Extensions additionalExtensions)
{
MessageImprint messageImprint = new MessageImprint(request.MessageImprintAlgID, request.MessageImprint.HashedMessage);
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 derObjectIdentifier = tsaPolicyOID;
if (request.ReqPolicy != null)
derObjectIdentifier = new DerObjectIdentifier(request.ReqPolicy);
if (derObjectIdentifier != null) {
X509Extensions x509Extensions = request.Extensions;
if (additionalExtensions != null) {
X509ExtensionsGenerator x509ExtensionsGenerator = new X509ExtensionsGenerator();
if (x509Extensions != null) {
foreach (DerObjectIdentifier extensionOid in x509Extensions.ExtensionOids) {
x509ExtensionsGenerator.AddExtension(extensionOid, x509Extensions.GetExtension(extensionOid));
}
}
foreach (DerObjectIdentifier extensionOid2 in additionalExtensions.ExtensionOids) {
x509ExtensionsGenerator.AddExtension(extensionOid2, additionalExtensions.GetExtension(extensionOid2));
}
x509Extensions = x509ExtensionsGenerator.Generate();
}
DerGeneralizedTime genTime2 = new DerGeneralizedTime(WithResolution(genTime, resolution));
TstInfo tstInfo = new TstInfo(derObjectIdentifier, messageImprint, new DerInteger(serialNumber), genTime2, accuracy, derBoolean, nonce, tsa, x509Extensions);
try {
CmsSignedDataGenerator cmsSignedDataGenerator = new CmsSignedDataGenerator();
byte[] derEncoded = tstInfo.GetDerEncoded();
if (request.CertReq) {
cmsSignedDataGenerator.AddCertificates(x509Certs);
cmsSignedDataGenerator.AddAttributeCertificates(x509AttrCerts);
}
cmsSignedDataGenerator.AddCrls(x509Crls);
foreach (KeyValuePair<DerObjectIdentifier, IStore<Asn1Encodable>> item in otherRevoc) {
cmsSignedDataGenerator.AddOtherRevocationInfos(item.Key, item.Value);
}
cmsSignedDataGenerator.AddSignerInfoGenerator(signerInfoGenerator);
return new TimeStampToken(cmsSignedDataGenerator.Generate(PkcsObjectIdentifiers.IdCTTstInfo.Id, new CmsProcessableByteArray(derEncoded), true));
} catch (CmsException innerException) {
throw new TspException("Error generating time-stamp token", innerException);
} catch (IOException innerException2) {
throw new TspException("Exception encoding info", innerException2);
}
}
throw new TspValidationException("request contains no policy", 256);
}
private static DateTime WithResolution(DateTime dateTime, Resolution resolution)
{
switch (resolution) {
case Resolution.R_SECONDS:
return DateTimeUtilities.WithPrecisionSecond(dateTime);
case Resolution.R_TENTHS_OF_SECONDS:
return DateTimeUtilities.WithPrecisionDecisecond(dateTime);
case Resolution.R_HUNDREDTHS_OF_SECONDS:
return DateTimeUtilities.WithPrecisionCentisecond(dateTime);
case Resolution.R_MILLISECONDS:
return DateTimeUtilities.WithPrecisionMillisecond(dateTime);
default:
throw new InvalidOperationException();
}
}
}
}