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

            cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber);

            SignerInfo firstSigner = cms.SignerInfos[0];

            using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.GetCertificate())
            {
                Action sign = () =>
                              firstSigner.ComputeCounterSignature(
                    new CmsSigner(
                        SubjectIdentifierType.NoSignature,
                        cert)
                {
                    IncludeOption = X509IncludeOption.None,
                });

                if (PlatformDetection.IsFullFramework)
                {
                    Assert.ThrowsAny <CryptographicException>(sign);
                }
                else
                {
                    sign();
                    cms.CheckHash();
                    Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true));
                    firstSigner.CheckSignature(true);
                }
            }
        }
        public static void AddFirstCounterSigner_NoSignature()
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber);

            SignerInfo firstSigner = cms.SignerInfos[0];

            // A certificate shouldn't really be required here, but on .NET Framework
            // it will prompt for the counter-signer's certificate if it's null,
            // even if the signature type is NoSignature.
            using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey())
            {
                firstSigner.ComputeCounterSignature(
                    new CmsSigner(
                        SubjectIdentifierType.NoSignature,
                        cert)
                {
                    IncludeOption = X509IncludeOption.None,
                });
            }

            Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true));
            cms.CheckHash();

            byte[] encoded = cms.Encode();
            cms = new SignedCms();
            cms.Decode(encoded);
            Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true));
            cms.CheckHash();

            firstSigner = cms.SignerInfos[0];
            firstSigner.CheckSignature(verifySignatureOnly: true);
            Assert.ThrowsAny <CryptographicException>(() => firstSigner.CheckHash());

            SignerInfo firstCounterSigner = firstSigner.CounterSignerInfos[0];

            Assert.ThrowsAny <CryptographicException>(() => firstCounterSigner.CheckSignature(true));

            if (PlatformDetection.IsFullFramework)
            {
                // NetFX's CheckHash only looks at top-level SignerInfos to find the
                // crypt32 CMS signer ID, so it fails on any check from a countersigner.
                Assert.ThrowsAny <CryptographicException>(() => firstCounterSigner.CheckHash());
            }
            else
            {
                firstCounterSigner.CheckHash();
            }
        }
        public static void AddCounterSignerToUnsortedAttributeSignature()
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.DigiCertTimeStampToken);

            // Assert.NoThrows
            cms.CheckSignature(true);

            SignerInfoCollection signers = cms.SignerInfos;

            Assert.Equal(1, signers.Count);
            SignerInfo signerInfo = signers[0];

            using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey())
            {
                signerInfo.ComputeCounterSignature(
                    new CmsSigner(
                        SubjectIdentifierType.IssuerAndSerialNumber,
                        cert));

                signerInfo.ComputeCounterSignature(
                    new CmsSigner(
                        SubjectIdentifierType.SubjectKeyIdentifier,
                        cert));
            }

            // Assert.NoThrows
            cms.CheckSignature(true);

            byte[] exported = cms.Encode();
            cms = new SignedCms();
            cms.Decode(exported);

            // Assert.NoThrows
            cms.CheckSignature(true);
        }
        public static void AddCounterSigner_DuplicateCert_RSA()
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber);
            Assert.Single(cms.Certificates);

            SignerInfo firstSigner = cms.SignerInfos[0];

            Assert.Empty(firstSigner.CounterSignerInfos);
            Assert.Empty(firstSigner.UnsignedAttributes);

            using (X509Certificate2 signerCert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey())
            {
                CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, signerCert);
                firstSigner.ComputeCounterSignature(signer);
            }

            Assert.Empty(firstSigner.CounterSignerInfos);
            Assert.Empty(firstSigner.UnsignedAttributes);

            SignerInfo firstSigner2 = cms.SignerInfos[0];

            Assert.Single(firstSigner2.CounterSignerInfos);
            Assert.Single(firstSigner2.UnsignedAttributes);

            SignerInfo counterSigner = firstSigner2.CounterSignerInfos[0];

            Assert.Equal(SubjectIdentifierType.IssuerAndSerialNumber, counterSigner.SignerIdentifier.Type);

            // On NetFx there will be two attributes, because Windows emits the
            // content-type attribute even for counter-signers.
            int expectedAttrCount = 1;

            // One of them is a V3 signer.
#if netfx
            expectedAttrCount = 2;
#endif
            Assert.Equal(expectedAttrCount, counterSigner.SignedAttributes.Count);
            Assert.Equal(Oids.MessageDigest, counterSigner.SignedAttributes[expectedAttrCount - 1].Oid.Value);

            Assert.Equal(firstSigner2.Certificate, counterSigner.Certificate);
            Assert.Single(cms.Certificates);

            counterSigner.CheckSignature(true);
            firstSigner2.CheckSignature(true);
            cms.CheckSignature(true);
        }
Beispiel #5
0
        public static void AddCounterSigner_RSA(SubjectIdentifierType identifierType)
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber);
            Assert.Single(cms.Certificates);

            SignerInfo firstSigner = cms.SignerInfos[0];

            Assert.Empty(firstSigner.CounterSignerInfos);
            Assert.Empty(firstSigner.UnsignedAttributes);

            using (X509Certificate2 signerCert = Certificates.RSA2048SignatureOnly.TryGetCertificateWithPrivateKey())
            {
                CmsSigner signer = new CmsSigner(identifierType, signerCert);
                firstSigner.ComputeCounterSignature(signer);
            }

            Assert.Empty(firstSigner.CounterSignerInfos);
            Assert.Empty(firstSigner.UnsignedAttributes);

            SignerInfo firstSigner2 = cms.SignerInfos[0];

            Assert.Single(firstSigner2.CounterSignerInfos);
            Assert.Single(firstSigner2.UnsignedAttributes);

            SignerInfo counterSigner = firstSigner2.CounterSignerInfos[0];

            Assert.Equal(identifierType, counterSigner.SignerIdentifier.Type);

            // On .NET Framework there will be two attributes, because Windows emits the
            // content-type attribute even for counter-signers.
            int expectedCount = 1;

#if NETFRAMEWORK
            expectedCount = 2;
#endif
            Assert.Equal(expectedCount, counterSigner.SignedAttributes.Count);
            Assert.Equal(Oids.MessageDigest, counterSigner.SignedAttributes[expectedCount - 1].Oid.Value);

            Assert.NotEqual(firstSigner2.Certificate, counterSigner.Certificate);
            Assert.Equal(2, cms.Certificates.Count);

            counterSigner.CheckSignature(true);
            firstSigner2.CheckSignature(true);
            cms.CheckSignature(true);
        }
        private static void AddSecondCounterSignature_NoSignature(bool withCertificate, bool addExtraCert)
        {
            X509Certificate2Collection certs;
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber);

            SignerInfo firstSigner = cms.SignerInfos[0];

            using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey())
                using (X509Certificate2 cert2 = Certificates.DHKeyAgree1.GetCertificate())
                {
                    firstSigner.ComputeCounterSignature(
                        new CmsSigner(cert)
                    {
                        IncludeOption = X509IncludeOption.None,
                    });

                    CmsSigner counterSigner;

                    if (withCertificate)
                    {
                        counterSigner = new CmsSigner(SubjectIdentifierType.NoSignature, cert);
                    }
                    else
                    {
                        counterSigner = new CmsSigner(SubjectIdentifierType.NoSignature);
                    }

                    if (addExtraCert)
                    {
                        counterSigner.Certificates.Add(cert2);
                    }

                    firstSigner.ComputeCounterSignature(counterSigner);

                    certs = cms.Certificates;

                    if (addExtraCert)
                    {
                        Assert.Equal(2, certs.Count);
                        Assert.NotEqual(cert2.RawData, certs[0].RawData);
                        Assert.Equal(cert2.RawData, certs[1].RawData);
                    }
                    else
                    {
                        Assert.Equal(1, certs.Count);
                        Assert.NotEqual(cert2.RawData, certs[0].RawData);
                    }
                }

            Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true));
            cms.CheckHash();

            byte[] encoded = cms.Encode();
            cms = new SignedCms();
            cms.Decode(encoded);
            Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true));
            cms.CheckHash();

            firstSigner = cms.SignerInfos[0];
            firstSigner.CheckSignature(verifySignatureOnly: true);
            Assert.ThrowsAny <CryptographicException>(() => firstSigner.CheckHash());

            // The NoSignature CounterSigner sorts first.
            SignerInfo firstCounterSigner = firstSigner.CounterSignerInfos[0];

            Assert.Equal(SubjectIdentifierType.NoSignature, firstCounterSigner.SignerIdentifier.Type);
            Assert.ThrowsAny <CryptographicException>(() => firstCounterSigner.CheckSignature(true));

            if (PlatformDetection.IsFullFramework)
            {
                // NetFX's CheckHash only looks at top-level SignerInfos to find the
                // crypt32 CMS signer ID, so it fails on any check from a countersigner.
                Assert.ThrowsAny <CryptographicException>(() => firstCounterSigner.CheckHash());
            }
            else
            {
                firstCounterSigner.CheckHash();
            }

            certs = cms.Certificates;

            if (addExtraCert)
            {
                Assert.Equal(2, certs.Count);
                Assert.Equal("CN=DfHelleKeyAgreement1", certs[1].SubjectName.Name);
            }
            else
            {
                Assert.Equal(1, certs.Count);
            }

            Assert.Equal("CN=RSAKeyTransferCapi1", certs[0].SubjectName.Name);
        }
        public static void AddCounterSigner_ECDSA(SubjectIdentifierType identifierType, string digestOid)
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber);
            Assert.Single(cms.Certificates);

            SignerInfo firstSigner = cms.SignerInfos[0];

            Assert.Empty(firstSigner.CounterSignerInfos);
            Assert.Empty(firstSigner.UnsignedAttributes);

            using (X509Certificate2 signerCert = Certificates.ECDsaP256Win.TryGetCertificateWithPrivateKey())
            {
                CmsSigner signer = new CmsSigner(identifierType, signerCert);
                signer.IncludeOption   = X509IncludeOption.EndCertOnly;
                signer.DigestAlgorithm = new Oid(digestOid, digestOid);
                firstSigner.ComputeCounterSignature(signer);
            }

            Assert.Empty(firstSigner.CounterSignerInfos);
            Assert.Empty(firstSigner.UnsignedAttributes);

            SignerInfo firstSigner2 = cms.SignerInfos[0];

            Assert.Single(firstSigner2.CounterSignerInfos);
            Assert.Single(firstSigner2.UnsignedAttributes);

            Assert.Single(cms.SignerInfos);
            Assert.Equal(2, cms.Certificates.Count);

            SignerInfo counterSigner = firstSigner2.CounterSignerInfos[0];

            int expectedVersion = identifierType == SubjectIdentifierType.IssuerAndSerialNumber ? 1 : 3;

            Assert.Equal(expectedVersion, counterSigner.Version);

            // On NetFx there will be two attributes, because Windows emits the
            // content-type attribute even for counter-signers.
            int expectedCount = 1;

#if netfx
            expectedCount = 2;
#endif
            Assert.Equal(expectedCount, counterSigner.SignedAttributes.Count);
            Assert.Equal(Oids.MessageDigest, counterSigner.SignedAttributes[expectedCount - 1].Oid.Value);

            Assert.NotEqual(firstSigner2.Certificate, counterSigner.Certificate);
            Assert.Equal(2, cms.Certificates.Count);

#if netcoreapp
            byte[] signature = counterSigner.GetSignature();
            Assert.NotEmpty(signature);
            // DSA PKIX signature format is a DER SEQUENCE.
            Assert.Equal(0x30, signature[0]);

            // ECDSA Oids are all under 1.2.840.10045.4.
            Assert.StartsWith("1.2.840.10045.4.", counterSigner.SignatureAlgorithm.Value);
#endif

            cms.CheckSignature(true);
            byte[] encoded = cms.Encode();
            cms.Decode(encoded);
            cms.CheckSignature(true);
        }
        public static void AddCounterSigner_DSA()
        {
            SignedCms cms = new SignedCms();

            cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber);
            Assert.Single(cms.Certificates);

            SignerInfo firstSigner = cms.SignerInfos[0];

            Assert.Empty(firstSigner.CounterSignerInfos);
            Assert.Empty(firstSigner.UnsignedAttributes);

            using (X509Certificate2 signerCert = Certificates.Dsa1024.TryGetCertificateWithPrivateKey())
            {
                CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, signerCert);
                signer.IncludeOption = X509IncludeOption.EndCertOnly;
                // Best compatibility for DSA is SHA-1 (FIPS 186-2)
                signer.DigestAlgorithm = new Oid(Oids.Sha1, Oids.Sha1);
                firstSigner.ComputeCounterSignature(signer);
            }

            Assert.Empty(firstSigner.CounterSignerInfos);
            Assert.Empty(firstSigner.UnsignedAttributes);

            SignerInfo firstSigner2 = cms.SignerInfos[0];

            Assert.Single(firstSigner2.CounterSignerInfos);
            Assert.Single(firstSigner2.UnsignedAttributes);

            Assert.Single(cms.SignerInfos);
            Assert.Equal(2, cms.Certificates.Count);

            SignerInfo counterSigner = firstSigner2.CounterSignerInfos[0];

            Assert.Equal(1, counterSigner.Version);

            // On NetFx there will be two attributes, because Windows emits the
            // content-type attribute even for counter-signers.
            int expectedCount = 1;

#if netfx
            expectedCount = 2;
#endif
            Assert.Equal(expectedCount, counterSigner.SignedAttributes.Count);
            Assert.Equal(Oids.MessageDigest, counterSigner.SignedAttributes[expectedCount - 1].Oid.Value);

            Assert.NotEqual(firstSigner2.Certificate, counterSigner.Certificate);
            Assert.Equal(2, cms.Certificates.Count);

#if netcoreapp
            byte[] signature = counterSigner.GetSignature();
            Assert.NotEmpty(signature);
            // DSA PKIX signature format is a DER SEQUENCE.
            Assert.Equal(0x30, signature[0]);
#endif

            cms.CheckSignature(true);
            byte[] encoded = cms.Encode();
            cms.Decode(encoded);
            cms.CheckSignature(true);
        }
        public static void CounterSigningReindexes()
        {
            ContentInfo content = new ContentInfo(new byte[] { 7 });
            SignedCms   cms     = new SignedCms(content);

            using (X509Certificate2 cert1 = Certificates.RSA2048SignatureOnly.TryGetCertificateWithPrivateKey())
                using (X509Certificate2 cert2 = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey())
                {
                    CmsSigner signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, cert1);
                    cms.ComputeSignature(signer);

                    SignerProfile yellow = new SignerProfile(
                        cert1,
                        SubjectIdentifierType.SubjectKeyIdentifier,
                        hasSignedAttrs: false,
                        hasUnsignedAttrs: false,
                        hasCounterSigners: false);

                    AssertSignerTraits(cms.SignerInfos[0], yellow);

                    signer.SignedAttributes.Add(new Pkcs9SigningTime());
                    signer.SignerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber;
                    cms.ComputeSignature(signer);

                    SignerProfile green = new SignerProfile(
                        cert1,
                        SubjectIdentifierType.IssuerAndSerialNumber,
                        hasSignedAttrs: true,
                        hasUnsignedAttrs: false,
                        hasCounterSigners: false);

                    // No reordering.  0 stayed 0, new entry becomes 1.
                    AssertSignerTraits(cms.SignerInfos[0], yellow);
                    AssertSignerTraits(cms.SignerInfos[1], green);

                    signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert2);
                    cms.ComputeSignature(signer);

                    SignerProfile grey = new SignerProfile(
                        cert2,
                        SubjectIdentifierType.IssuerAndSerialNumber,
                        hasSignedAttrs: false,
                        hasUnsignedAttrs: false,
                        hasCounterSigners: false);

                    // No reordering.  0 stayed 0, 1 stays 1, new entry is 2.
                    AssertSignerTraits(cms.SignerInfos[0], yellow);
                    AssertSignerTraits(cms.SignerInfos[1], green);
                    AssertSignerTraits(cms.SignerInfos[2], grey);

                    CmsSigner  counterSigner = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert1);
                    SignerInfo toCounterSign = cms.SignerInfos[0];
                    toCounterSign.ComputeCounterSignature(counterSigner);

                    // Reordering just happened.
                    // We counter-signed the first element, so it gets bigger by ~a signerinfo, or 100% bigger.
                    // The sizes of the three were
                    //   yellow: 311 bytes
                    //   green: 455 bytes (IssuerAndSerialNumber takes more bytes, and it has attributes)
                    //   grey: 212 bytes (1024-bit RSA signature instead of 2048-bit)
                    //
                    // Because yellow also contains cyan (444) bytes (then also some overhead) it has grown
                    // to 763 bytes.  So the size-sorted order (DER SET-OF sorting) is { grey, green, yellow }.

                    // Record that yellow gained a countersigner (and thus an unsigned attribute)
                    yellow.HasUnsignedAttrs  = true;
                    yellow.HasCounterSigners = true;

                    SignerProfile cyan = new SignerProfile(
                        cert1,
                        SubjectIdentifierType.IssuerAndSerialNumber,
                        hasSignedAttrs: true,
                        hasUnsignedAttrs: false,
                        hasCounterSigners: false);

                    AssertSignerTraits(cms.SignerInfos[0], grey);
                    AssertSignerTraits(cms.SignerInfos[1], green);
                    AssertSignerTraits(cms.SignerInfos[2], yellow);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], cyan);

                    counterSigner.UnsignedAttributes.Add(new Pkcs9SigningTime());
                    toCounterSign.ComputeCounterSignature(counterSigner);

                    SignerProfile red = new SignerProfile(
                        cert1,
                        SubjectIdentifierType.IssuerAndSerialNumber,
                        hasSignedAttrs: true,
                        hasUnsignedAttrs: true,
                        hasCounterSigners: false);

                    // Since "red" has one more attribute than "cyan", but they're otherwise the same
                    // it will sort later.

                    AssertSignerTraits(cms.SignerInfos[0], grey);
                    AssertSignerTraits(cms.SignerInfos[1], green);
                    AssertSignerTraits(cms.SignerInfos[2], yellow);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], cyan);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[1], red);

                    counterSigner.SignerIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier;
                    toCounterSign.ComputeCounterSignature(counterSigner);

                    SignerProfile clear = new SignerProfile(
                        cert1,
                        SubjectIdentifierType.SubjectKeyIdentifier,
                        hasSignedAttrs: true,
                        hasUnsignedAttrs: true,
                        hasCounterSigners: false);

                    // By changing from IssuerAndSerialNumber to SubjectKeyIdentifier, this copy will
                    // sort higher.  It saves so many bytes, in this specific case, that it goes first.

                    AssertSignerTraits(cms.SignerInfos[0], grey);
                    AssertSignerTraits(cms.SignerInfos[1], green);
                    AssertSignerTraits(cms.SignerInfos[2], yellow);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], clear);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[1], cyan);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[2], red);

                    // Now start removing things.

                    cms.SignerInfos[2].RemoveCounterSignature(1);

                    // Fairly predictable.
                    AssertSignerTraits(cms.SignerInfos[0], grey);
                    AssertSignerTraits(cms.SignerInfos[1], green);
                    AssertSignerTraits(cms.SignerInfos[2], yellow);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], clear);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[1], red);

                    cms.SignerInfos[2].RemoveCounterSignature(1);

                    // Fairly predictable.
                    AssertSignerTraits(cms.SignerInfos[0], grey);
                    AssertSignerTraits(cms.SignerInfos[1], green);
                    AssertSignerTraits(cms.SignerInfos[2], yellow);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], clear);

                    cms.SignerInfos[2].RemoveCounterSignature(0);

                    // We have removed the last counter-signer.
                    // yellow is now smaller than grey.
                    // But the document only re-normalizes on addition.

                    yellow.HasCounterSigners = false;
                    yellow.HasUnsignedAttrs  = false;

                    AssertSignerTraits(cms.SignerInfos[0], grey);
                    AssertSignerTraits(cms.SignerInfos[1], green);
                    AssertSignerTraits(cms.SignerInfos[2], yellow);

                    // Export/import to normalize. Everyone's back to their original size,
                    // but they were unsorted before. { grey, yellow, green } was the right order.
                    cms.Decode(cms.Encode());

                    AssertSignerTraits(cms.SignerInfos[0], grey);
                    AssertSignerTraits(cms.SignerInfos[1], yellow);
                    AssertSignerTraits(cms.SignerInfos[2], green);

                    cms.SignerInfos[0].ComputeCounterSignature(counterSigner);

                    // Move to the end of the line, Mr. Grey
                    grey.HasUnsignedAttrs  = true;
                    grey.HasCounterSigners = true;

                    AssertSignerTraits(cms.SignerInfos[0], yellow);
                    AssertSignerTraits(cms.SignerInfos[1], green);
                    AssertSignerTraits(cms.SignerInfos[2], grey);
                    AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], clear);
                }
        }