public static void SignerInfo_RemoveUnsignedAttributeFromCounterSigner_Removes()
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.OneRsaSignerTwoRsaCounterSigners);

            AsnEncodedData attribute1 = CreateTimestampToken(1);
            AsnEncodedData attribute2 = CreateTimestampToken(2);

            SignerInfo counterSigner = cms.SignerInfos[0].CounterSignerInfos[0];

            counterSigner.AddUnsignedAttribute(attribute1);
            counterSigner.AddUnsignedAttribute(attribute2);

            ReReadSignedCms(ref cms);

            SignerInfo signer = cms.SignerInfos[0];

            // attributes got sorted, therefore number changed
            Assert.Equal(2, signer.CounterSignerInfos.Count);
            Assert.Equal(0, signer.CounterSignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(1, signer.CounterSignerInfos[1].UnsignedAttributes.Count);
            Assert.Equal(2, signer.CounterSignerInfos[1].UnsignedAttributes[0].Values.Count);

            counterSigner = signer.CounterSignerInfos[1];
            counterSigner.RemoveUnsignedAttribute(counterSigner.UnsignedAttributes[0].Values[0]);

            // We didn't modify existing instances
            Assert.Equal(2, signer.CounterSignerInfos.Count);
            Assert.Equal(1, counterSigner.UnsignedAttributes.Count);
            Assert.Equal(2, counterSigner.UnsignedAttributes[0].Values.Count);

            // parent got updated
            Assert.Equal(0, signer.CounterSignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(1, signer.CounterSignerInfos[1].UnsignedAttributes.Count);

            // We did modify the state
            Assert.Equal(1, cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes.Count);
            Assert.Equal(1, cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes[0].Values.Count);

            ReReadSignedCms(ref cms);

            counterSigner = cms.SignerInfos[0].CounterSignerInfos[1];
            Assert.Equal(1, counterSigner.UnsignedAttributes.Count);
            Assert.Equal(1, counterSigner.UnsignedAttributes[0].Values.Count);
            counterSigner.RemoveUnsignedAttribute(counterSigner.UnsignedAttributes[0].Values[0]);

            // We didn't modify current instance
            Assert.Equal(1, counterSigner.UnsignedAttributes.Count);
            Assert.Equal(1, counterSigner.UnsignedAttributes[0].Values.Count);

            // We did modify the state
            Assert.Equal(0, cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes.Count);
        }
        public static void SignerInfo_AddOneUnsignedAttributeToCounterSigner_Adds()
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.OneRsaSignerTwoRsaCounterSigners);

            SignerInfo signer = cms.SignerInfos[0];

            Assert.Equal(2, signer.UnsignedAttributes.Count);
            Assert.Equal(2, signer.CounterSignerInfos.Count);

            SignerInfo counterSigner0 = signer.CounterSignerInfos[0];
            SignerInfo counterSigner1 = signer.CounterSignerInfos[1];

            Assert.Equal(0, counterSigner0.UnsignedAttributes.Count);
            Assert.Equal(0, counterSigner1.UnsignedAttributes.Count);

            AsnEncodedData attribute = CreateTimestampToken(1);

            counterSigner0.AddUnsignedAttribute(attribute);

            // we didn't modify existing instances
            Assert.Equal(2, signer.CounterSignerInfos.Count);
            Assert.Equal(0, counterSigner0.UnsignedAttributes.Count);
            Assert.Equal(0, counterSigner1.UnsignedAttributes.Count);

            // inner counter signers did get updated
            Assert.Equal(1, signer.CounterSignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(1, signer.CounterSignerInfos[0].UnsignedAttributes[0].Values.Count);
            Assert.Equal(0, signer.CounterSignerInfos[1].UnsignedAttributes.Count);

            // verify we didn't modify anything we shouldn't
            Assert.Equal(1, cms.SignerInfos.Count);
            Assert.Equal(2, cms.SignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(2, cms.SignerInfos[0].CounterSignerInfos.Count);

            // note: counter signers got sorted when encoded
            Assert.Equal(0, cms.SignerInfos[0].CounterSignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(1, cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes.Count);
            Assert.Equal(1, cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes[0].Values.Count);
            VerifyAttributesAreEqual(cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes[0].Values[0], attribute);

            ReReadSignedCms(ref cms);

            Assert.Equal(2, cms.SignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(2, cms.SignerInfos[0].CounterSignerInfos.Count);
            Assert.Equal(0, cms.SignerInfos[0].CounterSignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(1, cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes.Count);
            Assert.Equal(1, cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes[0].Values.Count);
            VerifyAttributesAreEqual(cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes[0].Values[0], attribute);
        }
Пример #3
0
        private async Task CreateTimeStamp(SignedCms signedCms)
        {
            // See: https://www.glennwatson.net/posts/rfc-3161-signing

            const string timeStampAuthorityUri = "http://time.certum.pl/";

            byte[] nonce = new byte[8];
            using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(nonce);
            }

            SignerInfo newSignerInfo        = signedCms.SignerInfos[0];
            Rfc3161TimestampRequest?request = Rfc3161TimestampRequest.CreateFromSignerInfo(
                newSignerInfo,
                HashAlgorithmName.SHA256,
                requestSignerCertificates: true,
                nonce: nonce);

            using HttpClient client             = new HttpClient();
            using ReadOnlyMemoryContent content = new ReadOnlyMemoryContent(request.Encode());
            content.Headers.ContentType         = new MediaTypeHeaderValue("application/timestamp-query");

            using HttpResponseMessage? httpResponse = await client.PostAsync(timeStampAuthorityUri, content).ConfigureAwait(false);

            if (!httpResponse.IsSuccessStatusCode)
            {
                throw new CryptographicException($"There was a error from the timestamp authority. It responded with {httpResponse.StatusCode} {(int)httpResponse.StatusCode}: {httpResponse.Content}");
            }

            if (httpResponse.Content.Headers.ContentType.MediaType != "application/timestamp-reply")
            {
                throw new CryptographicException("The reply from the time stamp server was in a invalid format.");
            }

            byte[]? data = await httpResponse.Content.ReadAsByteArrayAsync().ConfigureAwait(false);

            Rfc3161TimestampToken?timestampToken = request.ProcessResponse(data, out _);

            Oid signatureTimeStampOid = new Oid("1.2.840.113549.1.9.16.2.14");

            newSignerInfo.AddUnsignedAttribute(new AsnEncodedData(signatureTimeStampOid, timestampToken.AsSignedCms().Encode()));
        }
        public static void SignerInfo_AddRemoveUnsignedAttributeWithDetachtedSigner_Throws()
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.OneRsaSignerTwoRsaCounterSigners);

            // Detatch signer (and its counter signers)
            SignerInfo counterSigner = cms.SignerInfos[0].CounterSignerInfos[0];

            cms.RemoveSignature(0);

            // we shouldn't throw
            Assert.Equal(0, counterSigner.UnsignedAttributes.Count);

            AsnEncodedData attribute = CreateTimestampToken(1);

            Assert.Throws <CryptographicException>(() => counterSigner.AddUnsignedAttribute(attribute));
            Assert.Throws <CryptographicException>(() => counterSigner.RemoveUnsignedAttribute(attribute));
        }
        public static void SignerInfo_AddMultipleUnsignedAttributeToCounterSigner_Adds()
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.OneRsaSignerTwoRsaCounterSigners);

            SignerInfo signer = cms.SignerInfos[0];

            Assert.Equal(2, signer.UnsignedAttributes.Count);
            Assert.Equal(2, signer.CounterSignerInfos.Count);

            SignerInfo counterSigner0 = signer.CounterSignerInfos[0];
            SignerInfo counterSigner1 = signer.CounterSignerInfos[1];

            Assert.Equal(0, counterSigner0.UnsignedAttributes.Count);
            Assert.Equal(0, counterSigner1.UnsignedAttributes.Count);

            AsnEncodedData attribute1 = CreateTimestampToken(1);
            AsnEncodedData attribute2 = CreateTimestampToken(2);

            // note: using same instance to add
            counterSigner0.AddUnsignedAttribute(attribute1);
            SignerInfo signerAfterFirstCall = cms.SignerInfos[0];

            counterSigner0.AddUnsignedAttribute(attribute2);

            List <AsnEncodedData> expectedAttributes = new List <AsnEncodedData>()
            {
                attribute1,
                attribute2
            };

            // we didn't modify existing instances
            Assert.Equal(2, signer.CounterSignerInfos.Count);
            Assert.Equal(0, counterSigner0.UnsignedAttributes.Count);
            Assert.Equal(0, counterSigner1.UnsignedAttributes.Count);

            // inner counter signers did get updated
            Assert.Equal(1, signer.CounterSignerInfos[0].UnsignedAttributes.Count);

            // this is rather less obvious:
            //   - on first Add call we update the parent so the `signer` gets updated
            //   - on second Add call we also update the parent but `signer` is not actually the parent anymore
            Assert.Equal(1, signer.CounterSignerInfos[0].UnsignedAttributes[0].Values.Count);
            VerifyAttributesAreEqual(signer.CounterSignerInfos[0].UnsignedAttributes[0].Values[0], attribute1);
            Assert.Equal(0, signer.CounterSignerInfos[1].UnsignedAttributes.Count);

            Assert.Equal(0, signerAfterFirstCall.CounterSignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(1, signerAfterFirstCall.CounterSignerInfos[1].UnsignedAttributes.Count);
            Assert.Equal(2, signerAfterFirstCall.CounterSignerInfos[1].UnsignedAttributes[0].Values.Count);
            VerifyAttributesContainsAll(signerAfterFirstCall.CounterSignerInfos[1].UnsignedAttributes, expectedAttributes);

            // verify we didn't modify anything we shouldn't
            Assert.Equal(1, cms.SignerInfos.Count);
            Assert.Equal(2, cms.SignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(2, cms.SignerInfos[0].CounterSignerInfos.Count);

            // note: counter signers got sorted when encoded
            counterSigner0 = cms.SignerInfos[0].CounterSignerInfos[0];
            counterSigner1 = cms.SignerInfos[0].CounterSignerInfos[1];

            Assert.Equal(0, counterSigner0.UnsignedAttributes.Count);

            // attributes should be merged into a single one with two values
            Assert.Equal(1, counterSigner1.UnsignedAttributes.Count);
            Assert.Equal(2, counterSigner1.UnsignedAttributes[0].Values.Count);

            VerifyAttributesContainsAll(counterSigner1.UnsignedAttributes, expectedAttributes);

            ReReadSignedCms(ref cms);

            Assert.Equal(2, cms.SignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(2, cms.SignerInfos[0].CounterSignerInfos.Count);
            Assert.Equal(0, cms.SignerInfos[0].CounterSignerInfos[0].UnsignedAttributes.Count);
            Assert.Equal(1, cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes.Count);
            Assert.Equal(2, cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes[0].Values.Count);
            VerifyAttributesContainsAll(cms.SignerInfos[0].CounterSignerInfos[1].UnsignedAttributes, expectedAttributes);
        }