public void Read_WithMultipleEssCertIds_ReturnsSigningCertificate()
        {
            var bcEssCertId1         = CreateBcEssCertId("1");
            var bcEssCertId2         = CreateBcEssCertId("2");
            var bcEssCertId3         = CreateBcEssCertId("3");
            var bcSigningCertificate = new BcSigningCertificate(
                new DerSequence(new DerSequence(bcEssCertId1, bcEssCertId2, bcEssCertId3)));
            var bytes = bcSigningCertificate.GetDerEncoded();

            var signingCertificate = SigningCertificate.Read(bytes);

            Assert.Equal(3, signingCertificate.Certificates.Count);
            Assert.Null(signingCertificate.Policies);

            SignTestUtility.VerifyByteArrays(
                bcEssCertId1.GetCertHash(),
                signingCertificate.Certificates[0].CertificateHash);
            Assert.Null(signingCertificate.Certificates[0].IssuerSerial);

            SignTestUtility.VerifyByteArrays(
                bcEssCertId2.GetCertHash(),
                signingCertificate.Certificates[1].CertificateHash);
            Assert.Null(signingCertificate.Certificates[1].IssuerSerial);

            SignTestUtility.VerifyByteArrays(
                bcEssCertId3.GetCertHash(),
                signingCertificate.Certificates[2].CertificateHash);
            Assert.Null(signingCertificate.Certificates[2].IssuerSerial);
        }
        public void Read_WithPolicyInformation_ReturnsSigningCertificate()
        {
            var bcEssCertId          = CreateBcEssCertId("1");
            var bcPolicyInfo         = new BcPolicyInformation(new DerObjectIdentifier(Oids.AnyPolicy));
            var bcSigningCertificate = new BcSigningCertificate(
                new DerSequence(new DerSequence(bcEssCertId), new DerSequence(bcPolicyInfo)));
            var bytes = bcSigningCertificate.GetDerEncoded();

            var signingCertificate = SigningCertificate.Read(bytes);

            Assert.Equal(1, signingCertificate.Certificates.Count);
            Assert.Equal(1, signingCertificate.Policies.Count);

            var policyInfo = signingCertificate.Policies[0];

            Assert.Equal(bcPolicyInfo.PolicyIdentifier.ToString(), policyInfo.PolicyIdentifier.Value);
            Assert.Null(policyInfo.PolicyQualifiers);
        }
 public void Read_WithInvalidAsn1_Throws()
 {
     Assert.Throws <CryptographicException>(
         () => SigningCertificate.Read(new byte[] { 0x30, 0x0b }));
 }
        private static IX509CertificateChain GetCertificates(
            SignedCms signedCms,
            SignerInfo signerInfo,
            SigningCertificateRequirement signingCertificateRequirement,
            bool isIssuerSerialRequired,
            Errors errors,
            SigningSpecifications signingSpecifications,
            bool includeChain)
        {
            if (signedCms == null)
            {
                throw new ArgumentNullException(nameof(signedCms));
            }

            if (signingSpecifications == null)
            {
                throw new ArgumentNullException(nameof(signingSpecifications));
            }

            if (signerInfo.Certificate == null)
            {
                throw new SignatureException(errors.NoCertificate, errors.NoCertificateString);
            }

            /*
             *  The signing-certificate and signing-certificate-v2 attributes are described in RFC 2634 and RFC 5035.
             *
             *  Timestamps
             *  --------------------------------------------------
             *  RFC 3161 requires the signing-certificate attribute.  The RFC 5816 update introduces the newer
             *  signing-certificate-v2 attribute, which may replace or, for backwards compatibility, be present
             *  alongside the older signing-certificate attribute.
             *
             *  The issuerSerial field is not required, but should be validated if present.
             *
             *
             *  Author and repository signatures
             *  --------------------------------------------------
             *  RFC 5126 (CAdES) requires that exactly one of either of these attributes be present, and also requires that
             *  the issuerSerial field be present.
             *
             *
             *  Validation
             *  --------------------------------------------------
             *  For author and repository signatures:
             *
             * the signing-certificate attribute must not be present
             * the signing-certificate-v2 attribute be present
             * the issuerSerial field must be present
             *
             *
             *  References:
             *
             *      "Signing Certificate Attribute Definition", RFC 2634 section 5.4 (https://tools.ietf.org/html/rfc2634#section-5.4)
             *      "Certificate Identification", RFC 2634 section 5.4 (https://tools.ietf.org/html/rfc2634#section-5.4.1)
             *      "Enhanced Security Services (ESS) Update: Adding CertID Algorithm Agility", RFC 5035 (https://tools.ietf.org/html/rfc5035)
             *      "Request Format", RFC 3161 section 2.4.1 (https://tools.ietf.org/html/rfc3161#section-2.4.1)
             *      "Signature of Time-Stamp Token", RFC 5816 section 2.2.1 (https://tools.ietf.org/html/rfc5816#section-2.2.1)
             *      "Signing Certificate Reference Attributes", RFC 5126 section 5.7.3 (https://tools.ietf.org/html/rfc5126.html#section-5.7.3)
             *      "ESS signing-certificate Attribute Definition", RFC 5126 section 5.7.3.1 (https://tools.ietf.org/html/rfc5126.html#section-5.7.3.1)
             *      "ESS signing-certificate-v2 Attribute Definition", RFC 5126 section 5.7.3.2 (https://tools.ietf.org/html/rfc5126.html#section-5.7.3.2)
             */

            const string signingCertificateName   = "signing-certificate";
            const string signingCertificateV2Name = "signing-certificate-v2";

            CryptographicAttributeObject signingCertificateAttribute   = null;
            CryptographicAttributeObject signingCertificateV2Attribute = null;

            foreach (var attribute in signerInfo.SignedAttributes)
            {
                switch (attribute.Oid.Value)
                {
                case Oids.SigningCertificate:
                    if (signingCertificateAttribute != null)
                    {
                        throw new SignatureException(
                                  errors.InvalidSignature,
                                  string.Format(
                                      CultureInfo.CurrentCulture,
                                      Strings.MultipleAttributesDisallowed,
                                      signingCertificateName));
                    }

                    if (attribute.Values.Count != 1)
                    {
                        throw new SignatureException(
                                  errors.InvalidSignature,
                                  string.Format(
                                      CultureInfo.CurrentCulture,
                                      Strings.ExactlyOneAttributeValueRequired,
                                      signingCertificateName));
                    }

                    signingCertificateAttribute = attribute;
                    break;

                case Oids.SigningCertificateV2:
                    if (signingCertificateV2Attribute != null)
                    {
                        throw new SignatureException(
                                  errors.InvalidSignature,
                                  string.Format(
                                      CultureInfo.CurrentCulture,
                                      Strings.MultipleAttributesDisallowed,
                                      signingCertificateV2Name));
                    }

                    if (attribute.Values.Count != 1)
                    {
                        throw new SignatureException(
                                  errors.InvalidSignature,
                                  string.Format(
                                      CultureInfo.CurrentCulture,
                                      Strings.ExactlyOneAttributeValueRequired,
                                      signingCertificateV2Name));
                    }

                    signingCertificateV2Attribute = attribute;
                    break;
                }
            }

            switch (signingCertificateRequirement)
            {
            case SigningCertificateRequirement.OnlyV2:
            {
                if (signingCertificateAttribute != null)
                {
                    throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateAttributeMustNotBePresent);
                }

                if (signingCertificateV2Attribute == null)
                {
                    throw new SignatureException(
                              errors.InvalidSignature,
                              string.Format(CultureInfo.CurrentCulture,
                                            Strings.ExactlyOneAttributeRequired,
                                            signingCertificateV2Name));
                }
            }
            break;

            case SigningCertificateRequirement.EitherOrBoth:
                if (signingCertificateAttribute == null && signingCertificateV2Attribute == null)
                {
                    throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateV1OrV2AttributeMustBePresent);
                }
                break;
            }

            if (signingCertificateV2Attribute != null)
            {
                var reader = CreateDerSequenceReader(signingCertificateV2Attribute);
                var signingCertificateV2 = SigningCertificateV2.Read(reader);

                if (signingCertificateV2.Certificates.Count == 0)
                {
                    throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateV2Invalid);
                }

                foreach (var essCertIdV2 in signingCertificateV2.Certificates)
                {
                    if (!signingSpecifications.AllowedHashAlgorithmOids.Contains(
                            essCertIdV2.HashAlgorithm.Algorithm.Value,
                            StringComparer.Ordinal))
                    {
                        throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateV2UnsupportedHashAlgorithm);
                    }
                }

                if (!IsMatch(signerInfo.Certificate, signingCertificateV2.Certificates[0], errors, isIssuerSerialRequired))
                {
                    throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateV2CertificateNotFound);
                }
            }

            if (signingCertificateAttribute != null)
            {
                var reader             = CreateDerSequenceReader(signingCertificateAttribute);
                var signingCertificate = SigningCertificate.Read(reader);

                if (signingCertificate.Certificates.Count == 0)
                {
                    throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateInvalid);
                }

                if (!IsMatch(signerInfo.Certificate, signingCertificate.Certificates[0]))
                {
                    throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateCertificateNotFound);
                }
            }

            var certificates = GetCertificateChain(signerInfo.Certificate, signedCms.Certificates, includeChain);

            if (certificates == null || certificates.Count == 0)
            {
                throw new SignatureException(errors.ChainBuildingFailed, Strings.CertificateChainBuildFailed);
            }

            return(certificates);
        }