diff options
-rw-r--r-- | crypto/src/asn1/cms/OtherRevocationInfoFormat.cs | 8 | ||||
-rw-r--r-- | crypto/src/cms/CMSSignedData.cs | 62 | ||||
-rw-r--r-- | crypto/src/cms/CMSSignedDataParser.cs | 9 | ||||
-rw-r--r-- | crypto/src/cms/CMSSignedGenerator.cs | 17 | ||||
-rw-r--r-- | crypto/src/cms/CMSSignedHelper.cs | 26 | ||||
-rw-r--r-- | crypto/src/cms/CMSUtils.cs | 52 | ||||
-rw-r--r-- | crypto/src/cms/OriginatorInfoGenerator.cs | 59 | ||||
-rw-r--r-- | crypto/test/src/cms/test/CMSTestUtil.cs | 10 | ||||
-rw-r--r-- | crypto/test/src/cms/test/SignedDataStreamTest.cs | 112 |
9 files changed, 313 insertions, 42 deletions
diff --git a/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs b/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs index 78354896f..f6335cdac 100644 --- a/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs +++ b/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs @@ -1,6 +1,4 @@ -using System; - -namespace Org.BouncyCastle.Asn1.Cms +namespace Org.BouncyCastle.Asn1.Cms { public class OtherRevocationInfoFormat : Asn1Encodable @@ -44,8 +42,8 @@ namespace Org.BouncyCastle.Asn1.Cms */ public static OtherRevocationInfoFormat GetInstance(object obj) { - if (obj is OtherRevocationInfoFormat) - return (OtherRevocationInfoFormat)obj; + if (obj is OtherRevocationInfoFormat otherRevocationInfoFormat) + return otherRevocationInfoFormat; if (obj != null) return new OtherRevocationInfoFormat(Asn1Sequence.GetInstance(obj)); return null; diff --git a/crypto/src/cms/CMSSignedData.cs b/crypto/src/cms/CMSSignedData.cs index 3d4ce05a6..773e15be0 100644 --- a/crypto/src/cms/CMSSignedData.cs +++ b/crypto/src/cms/CMSSignedData.cs @@ -204,6 +204,11 @@ namespace Org.BouncyCastle.Cms return Helper.GetCrls(signedData.CRLs); } + public IStore<Asn1Encodable> GetOtherRevInfos(DerObjectIdentifier otherRevInfoFormat) + { + return Helper.GetOtherRevInfos(signedData.CRLs, otherRevInfoFormat); + } + /// <summary> /// Return the <c>DerObjectIdentifier</c> associated with the encapsulated /// content info structure carried in the signed data. @@ -308,7 +313,7 @@ namespace Org.BouncyCastle.Cms return cms; } - /** + /** * Replace the certificate and CRL information associated with this * CmsSignedData object with the new one passed in. * @@ -318,48 +323,69 @@ namespace Org.BouncyCastle.Cms * @return a new signed data object. * @exception CmsException if there is an error processing the stores */ - public static CmsSignedData ReplaceCertificatesAndCrls(CmsSignedData signedData, IStore<X509Certificate> x509Certs, - IStore<X509Crl> x509Crls, IStore<X509V2AttributeCertificate> x509AttrCerts) + public static CmsSignedData ReplaceCertificatesAndCrls(CmsSignedData signedData, + IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls) { - // - // copy - // - CmsSignedData cms = new CmsSignedData(signedData); + return ReplaceCertificatesAndRevocations(signedData, x509Certs, x509Crls, null, null); + } + + public static CmsSignedData ReplaceCertificatesAndCrls(CmsSignedData signedData, + IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls, + IStore<X509V2AttributeCertificate> x509AttrCerts) + { + return ReplaceCertificatesAndRevocations(signedData, x509Certs, x509Crls, x509AttrCerts, null); + } + + public static CmsSignedData ReplaceCertificatesAndRevocations(CmsSignedData signedData, + IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls, + IStore<X509V2AttributeCertificate> x509AttrCerts, IStore<OtherRevocationInfoFormat> otherRevocationInfos) + { + // + // copy + // + CmsSignedData cms = new CmsSignedData(signedData); // // replace the certs and crls in the SignedData object // Asn1Set certSet = null; - Asn1Set crlSet = null; + Asn1Set revocationSet = null; if (x509Certs != null || x509AttrCerts != null) { - var certs = new List<Asn1Encodable>(); - + var certificates = new List<Asn1Encodable>(); if (x509Certs != null) { - certs.AddRange(CmsUtilities.GetCertificatesFromStore(x509Certs)); + certificates.AddRange(CmsUtilities.GetCertificatesFromStore(x509Certs)); } if (x509AttrCerts != null) { - certs.AddRange(CmsUtilities.GetAttributeCertificatesFromStore(x509AttrCerts)); + certificates.AddRange(CmsUtilities.GetAttributeCertificatesFromStore(x509AttrCerts)); } - Asn1Set berSet = CmsUtilities.CreateBerSetFromList(certs); + Asn1Set berSet = CmsUtilities.CreateBerSetFromList(certificates); if (berSet.Count > 0) { certSet = berSet; } } - if (x509Crls != null) + if (x509Crls != null || otherRevocationInfos != null) { - var crls = CmsUtilities.GetCrlsFromStore(x509Crls); + var revocations = new List<Asn1Encodable>(); + if (x509Crls != null) + { + revocations.AddRange(CmsUtilities.GetCrlsFromStore(x509Crls)); + } + if (otherRevocationInfos != null) + { + revocations.AddRange(CmsUtilities.GetOtherRevocationInfosFromStore(otherRevocationInfos)); + } - Asn1Set berSet = CmsUtilities.CreateBerSetFromList(crls); + Asn1Set berSet = CmsUtilities.CreateBerSetFromList(revocations); if (berSet.Count > 0) { - crlSet = berSet; + revocationSet = berSet; } } @@ -371,7 +397,7 @@ namespace Org.BouncyCastle.Cms old.DigestAlgorithms, old.EncapContentInfo, certSet, - crlSet, + revocationSet, old.SignerInfos); // diff --git a/crypto/src/cms/CMSSignedDataParser.cs b/crypto/src/cms/CMSSignedDataParser.cs index 78e29e6a3..c5dc795a8 100644 --- a/crypto/src/cms/CMSSignedDataParser.cs +++ b/crypto/src/cms/CMSSignedDataParser.cs @@ -275,7 +275,14 @@ namespace Org.BouncyCastle.Cms return Helper.GetCrls(_crlSet); } - private void PopulateCertCrlSets() + public IStore<Asn1Encodable> GetOtherRevInfos(DerObjectIdentifier otherRevInfoFormat) + { + PopulateCertCrlSets(); + + return Helper.GetOtherRevInfos(_crlSet, otherRevInfoFormat); + } + + private void PopulateCertCrlSets() { if (_isCertCrlParsed) return; diff --git a/crypto/src/cms/CMSSignedGenerator.cs b/crypto/src/cms/CMSSignedGenerator.cs index 24af9b56a..fd40de469 100644 --- a/crypto/src/cms/CMSSignedGenerator.cs +++ b/crypto/src/cms/CMSSignedGenerator.cs @@ -588,6 +588,23 @@ namespace Org.BouncyCastle.Cms _crls.AddRange(CmsUtilities.GetCrlsFromStore(crlStore)); } + public void AddOtherRevocationInfo(OtherRevocationInfoFormat otherRevocationInfo) + { + CmsUtilities.ValidateOtherRevocationInfo(otherRevocationInfo); + _crls.Add(new DerTaggedObject(false, 1, otherRevocationInfo)); + } + + public void AddOtherRevocationInfos(IStore<OtherRevocationInfoFormat> otherRevocationInfoStore) + { + _crls.AddRange(CmsUtilities.GetOtherRevocationInfosFromStore(otherRevocationInfoStore)); + } + + public void AddOtherRevocationInfos(DerObjectIdentifier otherRevInfoFormat, + IStore<Asn1Encodable> otherRevInfoStore) + { + _crls.AddRange(CmsUtilities.GetOtherRevocationInfosFromStore(otherRevInfoStore, otherRevInfoFormat)); + } + /** * Add a store of precalculated signers to the generator. * diff --git a/crypto/src/cms/CMSSignedHelper.cs b/crypto/src/cms/CMSSignedHelper.cs index 79290846e..9db39549b 100644 --- a/crypto/src/cms/CMSSignedHelper.cs +++ b/crypto/src/cms/CMSSignedHelper.cs @@ -2,8 +2,10 @@ using System; using System.Collections.Generic; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.CryptoPro; using Org.BouncyCastle.Asn1.Eac; +using Org.BouncyCastle.Asn1.Esf; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; @@ -348,5 +350,29 @@ namespace Org.BouncyCastle.Cms } return CollectionUtilities.CreateStore(contents); } + + internal IStore<Asn1Encodable> GetOtherRevInfos(Asn1Set crlSet, DerObjectIdentifier otherRevInfoFormat) + { + var contents = new List<Asn1Encodable>(); + if (crlSet != null && otherRevInfoFormat != null) + { + foreach (Asn1Encodable ae in crlSet) + { + if (ae != null && ae.ToAsn1Object() is Asn1TaggedObject taggedObject) + { + if (taggedObject.HasContextTag(1)) + { + var otherRevocationInfo = OtherRevocationInfoFormat.GetInstance(taggedObject, false); + + if (otherRevInfoFormat.Equals(otherRevocationInfo.InfoFormat)) + { + contents.Add(otherRevocationInfo.Info); + } + } + } + } + } + return CollectionUtilities.CreateStore(contents); + } } } diff --git a/crypto/src/cms/CMSUtils.cs b/crypto/src/cms/CMSUtils.cs index 6800c1d2a..1a1577c4e 100644 --- a/crypto/src/cms/CMSUtils.cs +++ b/crypto/src/cms/CMSUtils.cs @@ -4,6 +4,7 @@ using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Ocsp; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.Utilities.IO; @@ -112,12 +113,46 @@ namespace Org.BouncyCastle.Cms foreach (var crl in crlStore.EnumerateMatches(null)) { result.Add(crl.CertificateList); - } + } } return result; } - internal static Asn1Set CreateBerSetFromList(IEnumerable<Asn1Encodable> elements) + internal static List<Asn1TaggedObject> GetOtherRevocationInfosFromStore( + IStore<OtherRevocationInfoFormat> otherRevocationInfoStore) + { + var result = new List<Asn1TaggedObject>(); + if (otherRevocationInfoStore != null) + { + foreach (var otherRevocationInfo in otherRevocationInfoStore.EnumerateMatches(null)) + { + ValidateOtherRevocationInfo(otherRevocationInfo); + + result.Add(new DerTaggedObject(false, 1, otherRevocationInfo)); + } + } + return result; + } + + internal static List<DerTaggedObject> GetOtherRevocationInfosFromStore(IStore<Asn1Encodable> otherRevInfoStore, + DerObjectIdentifier otherRevInfoFormat) + { + var result = new List<DerTaggedObject>(); + if (otherRevInfoStore != null && otherRevInfoFormat != null) + { + foreach (var otherRevInfo in otherRevInfoStore.EnumerateMatches(null)) + { + var otherRevocationInfo = new OtherRevocationInfoFormat(otherRevInfoFormat, otherRevInfo); + + ValidateOtherRevocationInfo(otherRevocationInfo); + + result.Add(new DerTaggedObject(false, 1, otherRevocationInfo)); + } + } + return result; + } + + internal static Asn1Set CreateBerSetFromList(IEnumerable<Asn1Encodable> elements) { Asn1EncodableVector v = new Asn1EncodableVector(); @@ -157,5 +192,16 @@ namespace Org.BouncyCastle.Cms TbsCertificateStructure tbsCert = GetTbsCertificateStructure(cert); return new IssuerAndSerialNumber(tbsCert.Issuer, tbsCert.SerialNumber.Value); } - } + + internal static void ValidateOtherRevocationInfo(OtherRevocationInfoFormat otherRevocationInfo) + { + if (CmsObjectIdentifiers.id_ri_ocsp_response.Equals(otherRevocationInfo.InfoFormat)) + { + OcspResponse ocspResponse = OcspResponse.GetInstance(otherRevocationInfo.Info); + + if (OcspResponseStatus.Successful != ocspResponse.ResponseStatus.IntValueExact) + throw new ArgumentException("cannot add unsuccessful OCSP response to CMS SignedData"); + } + } + } } diff --git a/crypto/src/cms/OriginatorInfoGenerator.cs b/crypto/src/cms/OriginatorInfoGenerator.cs index d7d24dcc4..ec6d2d8d8 100644 --- a/crypto/src/cms/OriginatorInfoGenerator.cs +++ b/crypto/src/cms/OriginatorInfoGenerator.cs @@ -1,9 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; -using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.X509; @@ -11,30 +9,63 @@ namespace Org.BouncyCastle.Cms { public class OriginatorInfoGenerator { - private readonly List<X509CertificateStructure> origCerts; - private readonly List<CertificateList> origCrls; + private readonly List<Asn1Encodable> origCerts; + private readonly List<Asn1Encodable> origCrls; public OriginatorInfoGenerator(X509Certificate origCert) { - this.origCerts = new List<X509CertificateStructure>(); + this.origCerts = new List<Asn1Encodable>{ origCert.CertificateStructure }; this.origCrls = null; - origCerts.Add(origCert.CertificateStructure); } - public OriginatorInfoGenerator(IStore<X509Certificate> origCerts) - : this(origCerts, null) + public OriginatorInfoGenerator(IStore<X509Certificate> x509Certs) + : this(x509Certs, null, null, null) { } - public OriginatorInfoGenerator(IStore<X509Certificate> origCerts, IStore<X509Crl> origCrls) + public OriginatorInfoGenerator(IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls) + : this(x509Certs, x509Crls, null, null) { - this.origCerts = CmsUtilities.GetCertificatesFromStore(origCerts); - this.origCrls = origCrls == null ? null : CmsUtilities.GetCrlsFromStore(origCrls); } - + + public OriginatorInfoGenerator(IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls, + IStore<X509V2AttributeCertificate> x509AttrCerts, IStore<OtherRevocationInfoFormat> otherRevocationInfos) + { + List<Asn1Encodable> certificates = null; + if (x509Certs != null || x509AttrCerts != null) + { + certificates = new List<Asn1Encodable>(); + if (x509Certs != null) + { + certificates.AddRange(CmsUtilities.GetCertificatesFromStore(x509Certs)); + } + if (x509AttrCerts != null) + { + certificates.AddRange(CmsUtilities.GetAttributeCertificatesFromStore(x509AttrCerts)); + } + } + + List<Asn1Encodable> revocations = null; + if (x509Crls != null || otherRevocationInfos != null) + { + revocations = new List<Asn1Encodable>(); + if (x509Crls != null) + { + revocations.AddRange(CmsUtilities.GetCrlsFromStore(x509Crls)); + } + if (otherRevocationInfos != null) + { + revocations.AddRange(CmsUtilities.GetOtherRevocationInfosFromStore(otherRevocationInfos)); + } + } + + this.origCerts = certificates; + this.origCrls = revocations; + } + public virtual OriginatorInfo Generate() { - Asn1Set certSet = CmsUtilities.CreateDerSetFromList(origCerts); + Asn1Set certSet = origCerts == null ? null : CmsUtilities.CreateDerSetFromList(origCerts); Asn1Set crlSet = origCrls == null ? null : CmsUtilities.CreateDerSetFromList(origCrls); return new OriginatorInfo(certSet, crlSet); } diff --git a/crypto/test/src/cms/test/CMSTestUtil.cs b/crypto/test/src/cms/test/CMSTestUtil.cs index e98810c84..e7ec50f53 100644 --- a/crypto/test/src/cms/test/CMSTestUtil.cs +++ b/crypto/test/src/cms/test/CMSTestUtil.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Text; +using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.CryptoPro; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; @@ -455,6 +456,15 @@ namespace Org.BouncyCastle.Cms.Tests return CollectionUtilities.CreateStore(crlList); } + internal static IStore<Asn1Encodable> MakeOtherRevocationInfoStore(byte[] ocspResponseBytes) + { + var otherRevocationInfoList = new List<Asn1Encodable> + { + Asn1Object.FromByteArray(ocspResponseBytes) + }; + return CollectionUtilities.CreateStore(otherRevocationInfoList); + } + private static AuthorityKeyIdentifier CreateAuthorityKeyId( AsymmetricKeyParameter _pubKey) { diff --git a/crypto/test/src/cms/test/SignedDataStreamTest.cs b/crypto/test/src/cms/test/SignedDataStreamTest.cs index 37f41783d..3d7892c6d 100644 --- a/crypto/test/src/cms/test/SignedDataStreamTest.cs +++ b/crypto/test/src/cms/test/SignedDataStreamTest.cs @@ -38,6 +38,40 @@ namespace Org.BouncyCastle.Cms.Tests private static X509Crl signCrl; private static X509Crl origCrl; + private static readonly byte[] OcspResponseBytes = Base64.Decode( + "MIIFnAoBAKCCBZUwggWRBgkrBgEFBQcwAQEEggWCMIIFfjCCARehgZ8wgZwx" + + "CzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEgcHJhZGVzaDESMBAGA1UE" + + "BxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAKBgNVBAsTA0FUQzEeMBwG" + + "A1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQwIgYJKoZIhvcNAQkBFhVv" + + "Y3NwQHRjcy1jYS50Y3MuY28uaW4YDzIwMDMwNDAyMTIzNDU4WjBiMGAwOjAJ" + + "BgUrDgMCGgUABBRs07IuoCWNmcEl1oHwIak1BPnX8QQUtGyl/iL9WJ1VxjxF" + + "j0hAwJ/s1AcCAQKhERgPMjAwMjA4MjkwNzA5MjZaGA8yMDAzMDQwMjEyMzQ1" + + "OFowDQYJKoZIhvcNAQEFBQADgYEAfbN0TCRFKdhsmvOdUoiJ+qvygGBzDxD/" + + "VWhXYA+16AphHLIWNABR3CgHB3zWtdy2j7DJmQ/R7qKj7dUhWLSqclAiPgFt" + + "QQ1YvSJAYfEIdyHkxv4NP0LSogxrumANcDyC9yt/W9yHjD2ICPBIqCsZLuLk" + + "OHYi5DlwWe9Zm9VFwCGgggPMMIIDyDCCA8QwggKsoAMCAQICAQYwDQYJKoZI" + + "hvcNAQEFBQAwgZQxFDASBgNVBAMTC1RDUy1DQSBPQ1NQMSYwJAYJKoZIhvcN" + + "AQkBFhd0Y3MtY2FAdGNzLWNhLnRjcy5jby5pbjEMMAoGA1UEChMDVENTMQww" + + "CgYDVQQLEwNBVEMxEjAQBgNVBAcTCUh5ZGVyYWJhZDEXMBUGA1UECBMOQW5k" + + "aHJhIHByYWRlc2gxCzAJBgNVBAYTAklOMB4XDTAyMDgyOTA3MTE0M1oXDTAz" + + "MDgyOTA3MTE0M1owgZwxCzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEg" + + "cHJhZGVzaDESMBAGA1UEBxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAK" + + "BgNVBAsTA0FUQzEeMBwGA1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQw" + + "IgYJKoZIhvcNAQkBFhVvY3NwQHRjcy1jYS50Y3MuY28uaW4wgZ8wDQYJKoZI" + + "hvcNAQEBBQADgY0AMIGJAoGBAM+XWW4caMRv46D7L6Bv8iwtKgmQu0SAybmF" + + "RJiz12qXzdvTLt8C75OdgmUomxp0+gW/4XlTPUqOMQWv463aZRv9Ust4f8MH" + + "EJh4ekP/NS9+d8vEO3P40ntQkmSMcFmtA9E1koUtQ3MSJlcs441JjbgUaVnm" + + "jDmmniQnZY4bU3tVAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADALBgNVHQ8E" + + "BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwkwNgYIKwYBBQUHAQEEKjAoMCYG" + + "CCsGAQUFBzABhhpodHRwOi8vMTcyLjE5LjQwLjExMDo3NzAwLzAtBgNVHR8E" + + "JjAkMCKgIKAehhxodHRwOi8vMTcyLjE5LjQwLjExMC9jcmwuY3JsMA0GCSqG" + + "SIb3DQEBBQUAA4IBAQB6FovM3B4VDDZ15o12gnADZsIk9fTAczLlcrmXLNN4" + + "PgmqgnwF0Ymj3bD5SavDOXxbA65AZJ7rBNAguLUo+xVkgxmoBH7R2sBxjTCc" + + "r07NEadxM3HQkt0aX5XYEl8eRoifwqYAI9h0ziZfTNes8elNfb3DoPPjqq6V" + + "mMg0f0iMS4W8LjNPorjRB+kIosa1deAGPhq0eJ8yr0/s2QR2/WFD5P4aXc8I" + + "KWleklnIImS3zqiPrq6tl2Bm8DZj7vXlTOwmraSQxUwzCKwYob1yGvNOUQTq" + + "pG6jxn7jgDawHU1+WjWQe4Q34/pWeGLysxTraMa+Ug9kPe+jy/qRX2xwvKBZ"); + private static AsymmetricCipherKeyPair SignKP { get { return signKP == null ? (signKP = CmsTestUtil.MakeKeyPair()) : signKP; } @@ -341,7 +375,83 @@ namespace Org.BouncyCastle.Cms.Tests Assert.IsTrue(col.Contains(OrigCrl)); } - [Test] + [Test] + public void TestCrlAndOtherRevocationInfoFormat() + { + MemoryStream bOut = new MemoryStream(); + + var x509Certs = CmsTestUtil.MakeCertStore(OrigCert, SignCert); + var x509Crls = CmsTestUtil.MakeCrlStore(SignCrl, OrigCrl); + var x509OtherRevocationInfos = CmsTestUtil.MakeOtherRevocationInfoStore(OcspResponseBytes); + + CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator(); + gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedGenerator.DigestSha1); + gen.AddCertificates(x509Certs); + gen.AddCrls(x509Crls); + gen.AddOtherRevocationInfos(CmsObjectIdentifiers.id_ri_ocsp_response, x509OtherRevocationInfos); + + Stream sigOut = gen.Open(bOut); + + byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage); + sigOut.Write(testBytes, 0, testBytes.Length); + + sigOut.Close(); + + CheckSigParseable(bOut.ToArray()); + + CmsSignedDataParser sp = new CmsSignedDataParser( + new CmsTypedStream(new MemoryStream(testBytes, false)), bOut.ToArray()); + + sp.GetSignedContent().Drain(); + + // compute expected content digest + byte[] hash = DigestUtilities.CalculateDigest("SHA1", testBytes); + + VerifySignatures(sp, hash); + + // + // try using existing signer + // + gen = new CmsSignedDataStreamGenerator(); + gen.AddSigners(sp.GetSignerInfos()); + gen.AddCertificates(sp.GetCertificates()); + gen.AddCrls(sp.GetCrls()); + + var spOtherRevocationInfos = sp.GetOtherRevInfos(CmsObjectIdentifiers.id_ri_ocsp_response); + gen.AddOtherRevocationInfos(CmsObjectIdentifiers.id_ri_ocsp_response, spOtherRevocationInfos); + + bOut.SetLength(0); + + sigOut = gen.Open(bOut, true); + sigOut.Write(testBytes, 0, testBytes.Length); + sigOut.Close(); + + VerifyEncodedData(bOut); + + // + // look for the CRLs + // + var crls = new List<X509Crl>(x509Crls.EnumerateMatches(null)); + + Assert.AreEqual(2, crls.Count); + Assert.IsTrue(crls.Contains(SignCrl)); + Assert.IsTrue(crls.Contains(OrigCrl)); + + // + // look for OtherRevocationInfo + // + var x509OtherRevocationInfoList = new List<Asn1Encodable>( + x509OtherRevocationInfos.EnumerateMatches(null)); + + Assert.AreEqual(1, x509OtherRevocationInfoList.Count); + + var spOtherRevocationInfoList = new List<Asn1Encodable>( + spOtherRevocationInfos.EnumerateMatches(null)); + + Assert.AreEqual(1, spOtherRevocationInfoList.Count); + } + + [Test] public void TestSha1WithRsaNonData() { MemoryStream bOut = new MemoryStream(); |