From 326817d43b7033ff124924642dec1e84148e898e Mon Sep 17 00:00:00 2001 From: mw Date: Fri, 28 Aug 2020 23:36:29 +1000 Subject: Updated TimeStampTokenGenerator --- crypto/src/cms/SignerInfoGenerator.cs | 11 + crypto/src/crypto/IDigestFactory.cs | 9 +- crypto/src/crypto/operators/DigestFactory.cs | 79 ++++ crypto/src/tsp/TimeStampToken.cs | 12 +- crypto/src/tsp/TimeStampTokenGenerator.cs | 591 +++++++++++++++++---------- 5 files changed, 472 insertions(+), 230 deletions(-) create mode 100644 crypto/src/crypto/operators/DigestFactory.cs (limited to 'crypto') diff --git a/crypto/src/cms/SignerInfoGenerator.cs b/crypto/src/cms/SignerInfoGenerator.cs index df8d1d0a1..786749cb5 100644 --- a/crypto/src/cms/SignerInfoGenerator.cs +++ b/crypto/src/cms/SignerInfoGenerator.cs @@ -58,6 +58,16 @@ namespace Org.BouncyCastle.Cms { this.certificate = certificate; } + + public SignerInfoGeneratorBuilder NewBuilder() + { + SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(); + builder.WithSignedAttributeGenerator(signedGen); + builder.WithUnsignedAttributeGenerator(unsignedGen); + builder.SetDirectSignature(isDirectSignature); + return builder; + } + } public class SignerInfoGeneratorBuilder @@ -69,6 +79,7 @@ namespace Org.BouncyCastle.Cms public SignerInfoGeneratorBuilder() { } + /** * If the passed in flag is true, the signer signature will be based on the data, not diff --git a/crypto/src/crypto/IDigestFactory.cs b/crypto/src/crypto/IDigestFactory.cs index b37bab90e..b46769cd3 100644 --- a/crypto/src/crypto/IDigestFactory.cs +++ b/crypto/src/crypto/IDigestFactory.cs @@ -2,12 +2,11 @@ namespace Org.BouncyCastle.Crypto { /// /// Base interface for operator factories that create stream-based digest calculators. - /// - /// The algorithm details/parameter type for the digest factory. - public interface IDigestFactory + /// + public interface IDigestFactory { /// The algorithm details object for calculators made by this factory. - A AlgorithmDetails { get ; } + object AlgorithmDetails { get ; } /// Return the size of the digest associated with this factory. /// The length of the digest produced by this calculators from this factory in bytes. @@ -19,6 +18,6 @@ namespace Org.BouncyCastle.Crypto /// and producing the digest block. /// /// A calculator producing an IBlockResult with the final digest in it. - IStreamCalculator CreateCalculator(); + IStreamCalculator CreateCalculator(); } } diff --git a/crypto/src/crypto/operators/DigestFactory.cs b/crypto/src/crypto/operators/DigestFactory.cs new file mode 100644 index 000000000..7624fdf43 --- /dev/null +++ b/crypto/src/crypto/operators/DigestFactory.cs @@ -0,0 +1,79 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Crypto.Tests; +using Org.BouncyCastle.Security; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; + +namespace Org.BouncyCastle.Crypto.Operators +{ + + + + public class DigestFactory : IDigestFactory + { + + public static DigestFactory Get(DerObjectIdentifier oid) + { + return new DigestFactory(DigestUtilities.GetDigest(oid), oid); + } + + public static DigestFactory Get(String mechanism) + { + DerObjectIdentifier oid = DigestUtilities.GetObjectIdentifier(mechanism); + return new DigestFactory(DigestUtilities.GetDigest(oid), oid); + } + + + private IDigest digest; + private DerObjectIdentifier oid; + + public DigestFactory(IDigest digest, DerObjectIdentifier oid) + { + this.digest = digest; + this.oid = oid; + } + + public object AlgorithmDetails => new AlgorithmIdentifier(oid); + + public int DigestLength => digest.GetDigestSize(); + + public IStreamCalculator CreateCalculator() => new DfDigestStream(digest); + + } + + + internal class DfDigestStream : IStreamCalculator + { + + private DigestSink stream; + + public DfDigestStream(IDigest digest) + { + stream = new DigestSink(digest); + } + + public Stream Stream => stream; + + public object GetResult() + { + byte[] result = new byte[stream.Digest.GetDigestSize()]; + stream.Digest.DoFinal(result, 0); + return new SimpleBlockResult(result); + } + + } + + + +} diff --git a/crypto/src/tsp/TimeStampToken.cs b/crypto/src/tsp/TimeStampToken.cs index 643813552..32f2523ce 100644 --- a/crypto/src/tsp/TimeStampToken.cs +++ b/crypto/src/tsp/TimeStampToken.cs @@ -85,9 +85,17 @@ namespace Org.BouncyCastle.Tsp if (attr != null) { - SigningCertificate signCert = SigningCertificate.GetInstance(attr.AttrValues[0]); - this.certID = new CertID(EssCertID.GetInstance(signCert.GetCerts()[0])); + if (attr.AttrValues[0] is SigningCertificateV2) + { + SigningCertificateV2 signCert = SigningCertificateV2.GetInstance(attr.AttrValues[0]); + this.certID = new CertID(EssCertIDv2.GetInstance(signCert.GetCerts()[0])); + } + else + { + SigningCertificate signCert = SigningCertificate.GetInstance(attr.AttrValues[0]); + this.certID = new CertID(EssCertID.GetInstance(signCert.GetCerts()[0])); + } } else { diff --git a/crypto/src/tsp/TimeStampTokenGenerator.cs b/crypto/src/tsp/TimeStampTokenGenerator.cs index 07eddd4b9..3441a18a2 100644 --- a/crypto/src/tsp/TimeStampTokenGenerator.cs +++ b/crypto/src/tsp/TimeStampTokenGenerator.cs @@ -1,14 +1,20 @@ using System; using System.Collections; using System.IO; - +using System.Runtime.InteropServices.ComTypes; 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.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Operators; +using Org.BouncyCastle.Crypto.Paddings; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Security.Certificates; @@ -18,228 +24,367 @@ 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 Asn1.Cms.AttributeTable signedAttr; - private Asn1.Cms.AttributeTable unsignedAttr; - private IX509Store x509Certs; - private IX509Store x509Crls; - - /** + 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 IX509Store x509Certs; + private IX509Store x509Crls; + private SignerInfoGenerator signerInfoGenerator; + IDigestFactory digestCalculator; + + /** * basic creation - only the default attributes will be included here. */ - public TimeStampTokenGenerator( - AsymmetricKeyParameter key, - X509Certificate cert, - string digestOID, - string tsaPolicyOID) - : this(key, cert, digestOID, tsaPolicyOID, null, null) - { - } - - /** - * create with a signer with extra signed/unsigned attributes. - */ - public TimeStampTokenGenerator( - AsymmetricKeyParameter key, - X509Certificate cert, - string digestOID, - string tsaPolicyOID, - Asn1.Cms.AttributeTable signedAttr, - Asn1.Cms.AttributeTable unsignedAttr) - { - this.key = key; - this.cert = cert; - this.digestOID = digestOID; - this.tsaPolicyOID = tsaPolicyOID; - this.unsignedAttr = unsignedAttr; - - TspUtil.ValidateCertificate(cert); - - // - // Add the ESSCertID attribute - // - IDictionary signedAttrs; - if (signedAttr != null) - { - signedAttrs = signedAttr.ToDictionary(); - } - else - { - signedAttrs = Platform.CreateHashtable(); - } - - try - { - byte[] hash = DigestUtilities.CalculateDigest("SHA-1", cert.GetEncoded()); - - EssCertID essCertid = new EssCertID(hash); - - Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute( - PkcsObjectIdentifiers.IdAASigningCertificate, - new DerSet(new SigningCertificate(essCertid))); - - signedAttrs[attr.AttrType] = attr; - } - catch (CertificateEncodingException e) - { - throw new TspException("Exception processing certificate.", e); - } - catch (SecurityUtilityException e) - { - throw new TspException("Can't find a SHA-1 implementation.", e); - } - - this.signedAttr = new Asn1.Cms.AttributeTable(signedAttrs); - } - - public void SetCertificates( - IX509Store certificates) - { - this.x509Certs = certificates; - } - - public void SetCrls( - IX509Store crls) - { - this.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 digestAlgOID = new DerObjectIdentifier(request.MessageImprintAlgOid); - - AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DerNull.Instance); - MessageImprint messageImprint = new MessageImprint(algID, 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 derOrdering = null; - if (ordering) - { - derOrdering = DerBoolean.GetInstance(ordering); - } - - DerInteger nonce = null; - if (request.Nonce != null) - { - nonce = new DerInteger(request.Nonce); - } - - DerObjectIdentifier tsaPolicy = new DerObjectIdentifier(tsaPolicyOID); - if (request.ReqPolicy != null) - { - tsaPolicy = new DerObjectIdentifier(request.ReqPolicy); - } - - TstInfo tstInfo = new TstInfo(tsaPolicy, messageImprint, - new DerInteger(serialNumber), new DerGeneralizedTime(genTime), accuracy, - derOrdering, nonce, tsa, request.Extensions); - - try - { - CmsSignedDataGenerator signedDataGenerator = new CmsSignedDataGenerator(); - - byte[] derEncodedTstInfo = tstInfo.GetDerEncoded(); - - if (request.CertReq) - { - signedDataGenerator.AddCertificates(x509Certs); - } - - signedDataGenerator.AddCrls(x509Crls); - signedDataGenerator.AddSigner(key, cert, digestOID, signedAttr, unsignedAttr); - - CmsSignedData signedData = signedDataGenerator.Generate( - PkcsObjectIdentifiers.IdCTTstInfo.Id, - new CmsProcessableByteArray(derEncodedTstInfo), - true); - - return new TimeStampToken(signedData); - } - catch (CmsException cmsEx) - { - throw new TspException("Error generating time-stamp token", cmsEx); - } - catch (IOException e) - { - throw new TspException("Exception encoding info", e); - } - catch (X509StoreException e) - { - throw new TspException("Exception handling CertStore", e); - } -// catch (InvalidAlgorithmParameterException e) -// { -// throw new TspException("Exception handling CertStore CRLs", e); -// } - } - } + 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) + { + + this.signerInfoGenerator = signerInfoGen; + this.digestCalculator = digestCalculator; + this.tsaPolicyOID = tsaPolicy.Id; + + if (signerInfoGenerator.certificate == null) + { + throw new ArgumentException("SignerInfoGenerator must have an associated certificate"); + } + + X509Certificate assocCert = signerInfoGenerator.certificate; + TspUtil.ValidateCertificate(assocCert); + + try + { + IStreamCalculator calculator = digestCalculator.CreateCalculator(); + Stream stream = calculator.Stream; + byte[] certEnc = assocCert.GetEncoded(); + stream.Write(certEnc, 0, certEnc.Length); + stream.Flush(); + stream.Close(); + + if (((AlgorithmIdentifier)digestCalculator.AlgorithmDetails).Algorithm.Equals(OiwObjectIdentifiers.IdSha1)) + { + EssCertID essCertID = new EssCertID( + ((IBlockResult)calculator.GetResult()).Collect(), + isIssuerSerialIncluded ? + new IssuerSerial( + new GeneralNames( + new GeneralName(assocCert.IssuerDN)), + new DerInteger(assocCert.SerialNumber)) : null); + + this.signerInfoGenerator = signerInfoGen.NewBuilder() + .WithSignedAttributeGenerator(new TableGen(signerInfoGen, essCertID)) + .Build(signerInfoGen.contentSigner, signerInfoGen.certificate); + } + else + { + AlgorithmIdentifier digestAlgID = new AlgorithmIdentifier( + ((AlgorithmIdentifier)digestCalculator.AlgorithmDetails).Algorithm); + + EssCertIDv2 essCertID = new EssCertIDv2( + ((IBlockResult)calculator.GetResult()).Collect(), + isIssuerSerialIncluded ? + new IssuerSerial( + new GeneralNames( + new GeneralName(assocCert.IssuerDN)), + new DerInteger(assocCert.SerialNumber)) : null); + + this.signerInfoGenerator = signerInfoGen.NewBuilder() + .WithSignedAttributeGenerator(new TableGen2(signerInfoGen, essCertID)) + .Build(signerInfoGen.contentSigner, signerInfoGen.certificate); + } + + } + catch (Exception ex) + { + throw new TspException("Exception processing certificate", ex); + } + } + + /** + * create with a signer with extra signed/unsigned attributes. + */ + public TimeStampTokenGenerator( + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + string tsaPolicyOID, + Asn1.Cms.AttributeTable signedAttr, + Asn1.Cms.AttributeTable unsignedAttr) : this( + makeInfoGenerator(key, cert, digestOID, signedAttr, unsignedAttr), + DigestFactory.Get(OiwObjectIdentifiers.IdSha1), + tsaPolicyOID != null?new DerObjectIdentifier(tsaPolicyOID):null, false) + { + + this.tsaPolicyOID = tsaPolicyOID; + + + } + + + internal static SignerInfoGenerator makeInfoGenerator( + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + + Asn1.Cms.AttributeTable signedAttr, + Asn1.Cms.AttributeTable unsignedAttr) + { + + + TspUtil.ValidateCertificate(cert); + + // + // Add the ESSCertID attribute + // + IDictionary signedAttrs; + if (signedAttr != null) + { + signedAttrs = signedAttr.ToDictionary(); + } + else + { + signedAttrs = Platform.CreateHashtable(); + } + + //try + //{ + // byte[] hash = DigestUtilities.CalculateDigest("SHA-1", cert.GetEncoded()); + + // EssCertID essCertid = new EssCertID(hash); + + // Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute( + // PkcsObjectIdentifiers.IdAASigningCertificate, + // new DerSet(new SigningCertificate(essCertid))); + + // signedAttrs[attr.AttrType] = attr; + //} + //catch (CertificateEncodingException e) + //{ + // throw new TspException("Exception processing certificate.", e); + //} + //catch (SecurityUtilityException e) + //{ + // throw new TspException("Can't find a SHA-1 implementation.", e); + //} + + + string digestName = CmsSignedHelper.Instance.GetDigestAlgName(digestOID); + string signatureName = digestName + "with" + CmsSignedHelper.Instance.GetEncryptionAlgName(CmsSignedHelper.Instance.GetEncOid(key, digestOID)); + + Asn1SignatureFactory sigfact = new Asn1SignatureFactory(signatureName, key); + return new SignerInfoGeneratorBuilder() + .WithSignedAttributeGenerator( + new DefaultSignedAttributeTableGenerator( + new Asn1.Cms.AttributeTable(signedAttrs))) + .WithUnsignedAttributeGenerator( + new SimpleAttributeTableGenerator(unsignedAttr)) + .Build(sigfact, cert); + } + + + public void SetCertificates( + IX509Store certificates) + { + this.x509Certs = certificates; + } + + public void SetCrls( + IX509Store crls) + { + this.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 digestAlgOID = new DerObjectIdentifier(request.MessageImprintAlgOid); + + AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DerNull.Instance); + MessageImprint messageImprint = new MessageImprint(algID, 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 derOrdering = null; + if (ordering) + { + derOrdering = DerBoolean.GetInstance(ordering); + } + + DerInteger nonce = null; + if (request.Nonce != null) + { + nonce = new DerInteger(request.Nonce); + } + + DerObjectIdentifier tsaPolicy = new DerObjectIdentifier(tsaPolicyOID); + if (request.ReqPolicy != null) + { + tsaPolicy = new DerObjectIdentifier(request.ReqPolicy); + } + + TstInfo tstInfo = new TstInfo(tsaPolicy, messageImprint, + new DerInteger(serialNumber), new DerGeneralizedTime(genTime), accuracy, + derOrdering, nonce, tsa, request.Extensions); + + try + { + CmsSignedDataGenerator signedDataGenerator = new CmsSignedDataGenerator(); + + byte[] derEncodedTstInfo = tstInfo.GetDerEncoded(); + + if (request.CertReq) + { + signedDataGenerator.AddCertificates(x509Certs); + } + + signedDataGenerator.AddCrls(x509Crls); + + signedDataGenerator.AddSignerInfoGenerator(signerInfoGenerator); + + CmsSignedData signedData = signedDataGenerator.Generate( + PkcsObjectIdentifiers.IdCTTstInfo.Id, + new CmsProcessableByteArray(derEncodedTstInfo), + true); + + return new TimeStampToken(signedData); + } + catch (CmsException cmsEx) + { + throw new TspException("Error generating time-stamp token", cmsEx); + } + catch (IOException e) + { + throw new TspException("Exception encoding info", e); + } + catch (X509StoreException e) + { + throw new TspException("Exception handling CertStore", e); + } + // catch (InvalidAlgorithmParameterException e) + // { + // throw new TspException("Exception handling CertStore CRLs", e); + // } + } + + + 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 Asn1.Cms.AttributeTable GetAttributes(IDictionary parameters) + { + Asn1.Cms.AttributeTable tab = infoGen.signedGen.GetAttributes(parameters); + if (tab[PkcsObjectIdentifiers.IdAASigningCertificate] == null) + { + return tab.Add(PkcsObjectIdentifiers.IdAASigningCertificate, new SigningCertificate(essCertID)); + } + return tab; + } + } + + 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 Asn1.Cms.AttributeTable GetAttributes(IDictionary parameters) + { + Asn1.Cms.AttributeTable tab = infoGen.signedGen.GetAttributes(parameters); + if (tab[PkcsObjectIdentifiers.IdAASigningCertificate] == null) + { + return tab.Add(PkcsObjectIdentifiers.IdAASigningCertificate, new SigningCertificateV2(essCertID)); + } + return tab; + } + } + } } -- cgit 1.4.1