Beispiel #1
0
        private SignerInfoCollection GetCounterSigners(AttributeAsn[] unsignedAttrs)
        {
            // Since each "attribute" can have multiple "attribute values" there's no real
            // correlation to a predictive size here.
            List <SignerInfo> signerInfos = new List <SignerInfo>();

            foreach (AttributeAsn attributeAsn in unsignedAttrs)
            {
                if (attributeAsn.AttrType.Value == Oids.CounterSigner)
                {
                    AsnReader reader     = new AsnReader(attributeAsn.AttrValues, AsnEncodingRules.BER);
                    AsnReader collReader = reader.ReadSetOf();

                    if (reader.HasData)
                    {
                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                    }

                    while (collReader.HasData)
                    {
                        SignerInfoAsn parsedData =
                            AsnSerializer.Deserialize <SignerInfoAsn>(collReader.GetEncodedValue(), AsnEncodingRules.BER);

                        SignerInfo signerInfo = new SignerInfo(ref parsedData, _document)
                        {
                            _parentSignerInfo = this
                        };

                        signerInfos.Add(signerInfo);
                    }
                }
            }

            return(new SignerInfoCollection(signerInfos.ToArray()));
        }
Beispiel #2
0
        internal SignerInfo(ref SignerInfoAsn parsedData, SignedCms ownerDocument)
        {
            Version                       = parsedData.Version;
            SignerIdentifier              = new SubjectIdentifier(parsedData.Sid);
            _digestAlgorithm              = parsedData.DigestAlgorithm.Algorithm;
            _signedAttributes             = parsedData.SignedAttributes;
            _signatureAlgorithm           = parsedData.SignatureAlgorithm.Algorithm;
            _signatureAlgorithmParameters = parsedData.SignatureAlgorithm.Parameters;
            _signature                    = parsedData.SignatureValue;
            _unsignedAttributes           = parsedData.UnsignedAttributes;

            _document = ownerDocument;
        }
Beispiel #3
0
        public void ComputeCounterSignature(CmsSigner signer)
        {
            if (_parentSignerInfo != null)
            {
                throw new CryptographicException(SR.Cryptography_Cms_NoCounterCounterSigner);
            }
            if (signer == null)
            {
                throw new ArgumentNullException(nameof(signer));
            }

            signer.CheckCertificateValue();

            int myIdx = _document.SignerInfos.FindIndexForSigner(this);

            if (myIdx < 0)
            {
                throw new CryptographicException(SR.Cryptography_Cms_SignerNotFound);
            }

            // Make sure that we're using the most up-to-date version of this that we can.
            SignerInfo effectiveThis = _document.SignerInfos[myIdx];
            X509Certificate2Collection chain;
            SignerInfoAsn newSignerInfo = signer.Sign(effectiveThis._signature, null, false, out chain);

            AttributeAsn newUnsignedAttr;

            using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
            {
                writer.PushSetOf();
                AsnSerializer.Serialize(newSignerInfo, writer);
                writer.PopSetOf();

                newUnsignedAttr = new AttributeAsn
                {
                    AttrType   = new Oid(Oids.CounterSigner, Oids.CounterSigner),
                    AttrValues = writer.Encode(),
                };
            }

            ref SignedDataAsn signedData = ref _document.GetRawData();
Beispiel #4
0
        internal SignerInfo(ref SignerInfoAsn parsedData, SignedCms ownerDocument)
        {
            Version                       = parsedData.Version;
            SignerIdentifier              = new SubjectIdentifier(parsedData.Sid);
            _digestAlgorithm              = parsedData.DigestAlgorithm.Algorithm;
            _signedAttributesMemory       = parsedData.SignedAttributes;
            _signatureAlgorithm           = parsedData.SignatureAlgorithm.Algorithm;
            _signatureAlgorithmParameters = parsedData.SignatureAlgorithm.Parameters;
            _signature                    = parsedData.SignatureValue;
            _unsignedAttributes           = parsedData.UnsignedAttributes;

            if (_signedAttributesMemory.HasValue)
            {
                SignedAttributesSet signedSet = SignedAttributesSet.Decode(
                    _signedAttributesMemory.Value,
                    AsnEncodingRules.BER);

                _signedAttributes = signedSet.SignedAttributes;
                Debug.Assert(_signedAttributes != null);
            }

            _document = ownerDocument;
        }
Beispiel #5
0
        internal SignerInfoAsn Sign(
            ReadOnlyMemory <byte> data,
            string contentTypeOid,
            bool silent,
            out X509Certificate2Collection chainCerts)
        {
            HashAlgorithmName hashAlgorithmName = PkcsHelpers.GetDigestAlgorithm(DigestAlgorithm);
            IncrementalHash   hasher            = IncrementalHash.CreateHash(hashAlgorithmName);

            hasher.AppendData(data.Span);
            byte[] dataHash = hasher.GetHashAndReset();

            SignerInfoAsn newSignerInfo = new SignerInfoAsn();

            newSignerInfo.DigestAlgorithm.Algorithm = DigestAlgorithm;

            // If the user specified attributes (not null, count > 0) we need attributes.
            // If the content type is null we're counter-signing, and need the message digest attr.
            // If the content type is otherwise not-data we need to record it as the content-type attr.
            if (SignedAttributes?.Count > 0 || contentTypeOid != Oids.Pkcs7Data)
            {
                List <AttributeAsn> signedAttrs = BuildAttributes(SignedAttributes);

                using (var writer = new AsnWriter(AsnEncodingRules.DER))
                {
                    writer.WriteOctetString(dataHash);
                    signedAttrs.Add(
                        new AttributeAsn
                    {
                        AttrType   = new Oid(Oids.MessageDigest, Oids.MessageDigest),
                        AttrValues = new[] { new ReadOnlyMemory <byte>(writer.Encode()) },
                    });
                }

                if (contentTypeOid != null)
                {
                    using (var writer = new AsnWriter(AsnEncodingRules.DER))
                    {
                        writer.WriteObjectIdentifier(contentTypeOid);
                        signedAttrs.Add(
                            new AttributeAsn
                        {
                            AttrType   = new Oid(Oids.ContentType, Oids.ContentType),
                            AttrValues = new[] { new ReadOnlyMemory <byte>(writer.Encode()) },
                        });
                    }
                }

                // Use the serializer/deserializer to DER-normalize the attribute order.
                SignedAttributesSet signedAttrsSet = new SignedAttributesSet();
                signedAttrsSet.SignedAttributes = PkcsHelpers.NormalizeAttributeSet(
                    signedAttrs.ToArray(),
                    normalized => hasher.AppendData(normalized));

                // Since this contains user data in a context where BER is permitted, use BER.
                // There shouldn't be any observable difference here between BER and DER, though,
                // since the top level fields were written by NormalizeSet.
                using (AsnWriter attrsWriter = new AsnWriter(AsnEncodingRules.BER))
                {
                    signedAttrsSet.Encode(attrsWriter);
                    newSignerInfo.SignedAttributes = attrsWriter.Encode();
                }

                dataHash = hasher.GetHashAndReset();
            }

            switch (SignerIdentifierType)
            {
            case SubjectIdentifierType.IssuerAndSerialNumber:
                byte[] serial = Certificate.GetSerialNumber();
                Array.Reverse(serial);

                newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn
                {
                    Issuer       = Certificate.IssuerName.RawData,
                    SerialNumber = serial,
                };

                newSignerInfo.Version = 1;
                break;

            case SubjectIdentifierType.SubjectKeyIdentifier:
                newSignerInfo.Sid.SubjectKeyIdentifier = PkcsPal.Instance.GetSubjectKeyIdentifier(Certificate);
                newSignerInfo.Version = 3;
                break;

            case SubjectIdentifierType.NoSignature:
                newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn
                {
                    Issuer       = SubjectIdentifier.DummySignerEncodedValue,
                    SerialNumber = new byte[1],
                };
                newSignerInfo.Version = 1;
                break;

            default:
                Debug.Fail($"Unresolved SignerIdentifierType value: {SignerIdentifierType}");
                throw new CryptographicException();
            }

            if (UnsignedAttributes != null && UnsignedAttributes.Count > 0)
            {
                List <AttributeAsn> attrs = BuildAttributes(UnsignedAttributes);

                newSignerInfo.UnsignedAttributes = PkcsHelpers.NormalizeAttributeSet(attrs.ToArray());
            }

            bool signed;
            Oid  signatureAlgorithm;
            ReadOnlyMemory <byte> signatureValue;

            if (SignerIdentifierType == SubjectIdentifierType.NoSignature)
            {
                signatureAlgorithm = new Oid(Oids.NoSignature, null);
                signatureValue     = dataHash;
                signed             = true;
            }
            else
            {
                signed = CmsSignature.Sign(
                    dataHash,
                    hashAlgorithmName,
                    Certificate,
                    PrivateKey,
                    silent,
                    out signatureAlgorithm,
                    out signatureValue);
            }

            if (!signed)
            {
                throw new CryptographicException(SR.Cryptography_Cms_CannotDetermineSignatureAlgorithm);
            }

            newSignerInfo.SignatureValue = signatureValue;
            newSignerInfo.SignatureAlgorithm.Algorithm = signatureAlgorithm;

            X509Certificate2Collection certs = new X509Certificate2Collection();

            certs.AddRange(Certificates);

            if (SignerIdentifierType != SubjectIdentifierType.NoSignature)
            {
                if (IncludeOption == X509IncludeOption.EndCertOnly)
                {
                    certs.Add(Certificate);
                }
                else if (IncludeOption != X509IncludeOption.None)
                {
                    X509Chain chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;

                    if (!chain.Build(Certificate))
                    {
                        foreach (X509ChainStatus status in chain.ChainStatus)
                        {
                            if (status.Status == X509ChainStatusFlags.PartialChain)
                            {
                                throw new CryptographicException(SR.Cryptography_Cms_IncompleteCertChain);
                            }
                        }
                    }

                    X509ChainElementCollection elements = chain.ChainElements;
                    int count = elements.Count;
                    int last  = count - 1;

                    if (last == 0)
                    {
                        // If there's always one cert treat it as EE, not root.
                        last = -1;
                    }

                    for (int i = 0; i < count; i++)
                    {
                        X509Certificate2 cert = elements[i].Certificate;

                        if (i == last &&
                            IncludeOption == X509IncludeOption.ExcludeRoot &&
                            cert.SubjectName.RawData.AsSpan().SequenceEqual(cert.IssuerName.RawData))
                        {
                            break;
                        }

                        certs.Add(cert);
                    }
                }
            }

            chainCerts = certs;
            return(newSignerInfo);
        }
Beispiel #6
0
        public void ComputeSignature(CmsSigner signer, bool silent)
        {
            if (signer == null)
            {
                throw new ArgumentNullException(nameof(signer));
            }

            // While it shouldn't be possible to change the length of ContentInfo.Content
            // after it's built, use the property at this stage, then use the saved value
            // (if applicable) after this point.
            if (ContentInfo.Content.Length == 0)
            {
                throw new CryptographicException(SR.Cryptography_Cms_Sign_Empty_Content);
            }

            if (_hasData && signer.SignerIdentifierType == SubjectIdentifierType.NoSignature)
            {
                // Even if all signers have been removed, throw if doing a NoSignature signature
                // on a loaded (from file, or from first signature) document.
                //
                // This matches the .NET Framework behavior.
                throw new CryptographicException(SR.Cryptography_Cms_Sign_No_Signature_First_Signer);
            }

            if (signer.Certificate == null && signer.SignerIdentifierType != SubjectIdentifierType.NoSignature)
            {
                if (silent)
                {
                    // .NET Framework compatibility, silent disallows prompting, so throws InvalidOperationException
                    // in this state.
                    //
                    // The message is different than on NetFX, because the resource string was for
                    // enveloped CMS recipients (and the other site which would use that resource
                    // is unreachable code due to CmsRecipient's ctor guarding against null certificates)
                    throw new InvalidOperationException(SR.Cryptography_Cms_NoSignerCertSilent);
                }

                // Otherwise, PNSE. .NET Core doesn't support launching the cert picker UI.
                throw new PlatformNotSupportedException(SR.Cryptography_Cms_NoSignerCert);
            }

            // If we had content already, use that now.
            // (The second signer doesn't inherit edits to signedCms.ContentInfo.Content)
            ReadOnlyMemory <byte> content = _heldContent ?? ContentInfo.Content;
            string contentType            = _contentType ?? ContentInfo.ContentType.Value ?? Oids.Pkcs7Data;

            X509Certificate2Collection chainCerts;
            SignerInfoAsn newSigner   = signer.Sign(content, contentType, silent, out chainCerts);
            bool          firstSigner = false;

            if (!_hasData)
            {
                firstSigner = true;

                _signedData = new SignedDataAsn
                {
                    DigestAlgorithms = Array.Empty <AlgorithmIdentifierAsn>(),
                    SignerInfos      = Array.Empty <SignerInfoAsn>(),
                    EncapContentInfo = new EncapsulatedContentInfoAsn {
                        ContentType = contentType
                    },
                };

                // Since we're going to call Decode before this method exits we don't need to save
                // the copy of _heldContent or _contentType here if we're attached.
                if (!Detached)
                {
                    using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
                    {
                        writer.WriteOctetString(content.Span);

                        _signedData.EncapContentInfo.Content = writer.Encode();
                    }
                }

                _hasData = true;
            }

            int newIdx = _signedData.SignerInfos.Length;

            Array.Resize(ref _signedData.SignerInfos, newIdx + 1);
            _signedData.SignerInfos[newIdx] = newSigner;
            UpdateCertificatesFromAddition(chainCerts);
            ConsiderDigestAddition(newSigner.DigestAlgorithm);
            UpdateMetadata();

            if (firstSigner)
            {
                Reencode();

                Debug.Assert(_heldContent != null);
                Debug.Assert(_contentType == contentType);
            }
        }
Beispiel #7
0
        public void ComputeSignature(CmsSigner signer, bool silent)
        {
            if (signer == null)
            {
                throw new ArgumentNullException(nameof(signer));
            }

            // While it shouldn't be possible to change the length of ContentInfo.Content
            // after it's built, use the property at this stage, then use the saved value
            // (if applicable) after this point.
            if (ContentInfo.Content.Length == 0)
            {
                throw new CryptographicException(SR.Cryptography_Cms_Sign_Empty_Content);
            }

            // If we had content already, use that now.
            // (The second signer doesn't inherit edits to signedCms.ContentInfo.Content)
            ReadOnlyMemory <byte> content = _heldContent ?? ContentInfo.Content;
            string contentType            = _contentType ?? ContentInfo.ContentType.Value ?? Oids.Pkcs7Data;

            X509Certificate2Collection chainCerts;
            SignerInfoAsn newSigner   = signer.Sign(content, contentType, silent, out chainCerts);
            bool          firstSigner = false;

            if (!_hasData)
            {
                firstSigner = true;

                _signedData = new SignedDataAsn
                {
                    DigestAlgorithms = Array.Empty <AlgorithmIdentifierAsn>(),
                    SignerInfos      = Array.Empty <SignerInfoAsn>(),
                    EncapContentInfo = new EncapsulatedContentInfoAsn {
                        ContentType = contentType
                    },
                };

                // Since we're going to call Decode before this method exits we don't need to save
                // the copy of _heldContent or _contentType here if we're attached.
                if (!Detached)
                {
                    using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
                    {
                        writer.WriteOctetString(content.Span);

                        _signedData.EncapContentInfo.Content = writer.Encode();
                    }
                }

                _hasData = true;
            }

            int newIdx = _signedData.SignerInfos.Length;

            Array.Resize(ref _signedData.SignerInfos, newIdx + 1);
            _signedData.SignerInfos[newIdx] = newSigner;
            UpdateCertificatesFromAddition(chainCerts);
            ConsiderDigestAddition(newSigner.DigestAlgorithm);
            UpdateMetadata();

            if (firstSigner)
            {
                Reencode();

                Debug.Assert(_heldContent != null);
                Debug.Assert(_contentType == contentType);
            }
        }
Beispiel #8
0
        internal SignerInfoAsn Sign(
            ReadOnlyMemory <byte> data,
            string contentTypeOid,
            bool silent,
            out X509Certificate2Collection chainCerts)
        {
            HashAlgorithmName hashAlgorithmName = Helpers.GetDigestAlgorithm(DigestAlgorithm);
            IncrementalHash   hasher            = IncrementalHash.CreateHash(hashAlgorithmName);

            hasher.AppendData(data.Span);
            byte[] dataHash = hasher.GetHashAndReset();

            SignerInfoAsn newSignerInfo = new SignerInfoAsn();

            newSignerInfo.DigestAlgorithm.Algorithm = DigestAlgorithm;

            if ((SignedAttributes != null && SignedAttributes.Count > 0) || contentTypeOid == null)
            {
                List <AttributeAsn> signedAttrs = BuildAttributes(SignedAttributes);

                using (var writer = new AsnWriter(AsnEncodingRules.DER))
                {
                    writer.PushSetOf();
                    writer.WriteOctetString(dataHash);
                    writer.PopSetOf();

                    signedAttrs.Add(
                        new AttributeAsn
                    {
                        AttrType   = new Oid(Oids.MessageDigest, Oids.MessageDigest),
                        AttrValues = writer.Encode(),
                    });
                }

                if (contentTypeOid != null)
                {
                    using (var writer = new AsnWriter(AsnEncodingRules.DER))
                    {
                        writer.PushSetOf();
                        writer.WriteObjectIdentifier(contentTypeOid);
                        writer.PopSetOf();

                        signedAttrs.Add(
                            new AttributeAsn
                        {
                            AttrType   = new Oid(Oids.ContentType, Oids.ContentType),
                            AttrValues = writer.Encode(),
                        });
                    }
                }

                // Use the serializer/deserializer to DER-normalize the attribute order.
                newSignerInfo.SignedAttributes = Helpers.NormalizeSet(
                    signedAttrs.ToArray(),
                    normalized =>
                {
                    AsnReader reader = new AsnReader(normalized, AsnEncodingRules.DER);
                    hasher.AppendData(reader.PeekContentBytes().Span);
                });

                dataHash = hasher.GetHashAndReset();
            }

            switch (SignerIdentifierType)
            {
            case SubjectIdentifierType.IssuerAndSerialNumber:
                byte[] serial = Certificate.GetSerialNumber();
                Array.Reverse(serial);

                newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn
                {
                    Issuer       = Certificate.IssuerName.RawData,
                    SerialNumber = serial,
                };

                newSignerInfo.Version = 1;
                break;

            case SubjectIdentifierType.SubjectKeyIdentifier:
                newSignerInfo.Sid.SubjectKeyIdentifier = Certificate.GetSubjectKeyIdentifier();
                newSignerInfo.Version = 3;
                break;

            case SubjectIdentifierType.NoSignature:
                newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn
                {
                    Issuer       = SubjectIdentifier.DummySignerEncodedValue,
                    SerialNumber = new byte[1],
                };
                newSignerInfo.Version = 1;
                break;

            default:
                Debug.Fail($"Unresolved SignerIdentifierType value: {SignerIdentifierType}");
                throw new CryptographicException();
            }

            if (UnsignedAttributes != null && UnsignedAttributes.Count > 0)
            {
                List <AttributeAsn> attrs = BuildAttributes(UnsignedAttributes);

                newSignerInfo.UnsignedAttributes = Helpers.NormalizeSet(attrs.ToArray());
            }

            bool signed = CmsSignature.Sign(
                dataHash,
                hashAlgorithmName,
                Certificate,
                PrivateKey,
                silent,
                out Oid signatureAlgorithm,
                out ReadOnlyMemory <byte> signatureValue);

            if (!signed)
            {
                throw new CryptographicException(SR.Cryptography_Cms_CannotDetermineSignatureAlgorithm);
            }

            newSignerInfo.SignatureValue = signatureValue;
            newSignerInfo.SignatureAlgorithm.Algorithm = signatureAlgorithm;

            X509Certificate2Collection certs = new X509Certificate2Collection();

            certs.AddRange(Certificates);

            if (SignerIdentifierType != SubjectIdentifierType.NoSignature)
            {
                if (IncludeOption == X509IncludeOption.EndCertOnly)
                {
                    certs.Add(Certificate);
                }
                else if (IncludeOption != X509IncludeOption.None)
                {
                    X509Chain chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;

                    if (!chain.Build(Certificate))
                    {
                        foreach (X509ChainStatus status in chain.ChainStatus)
                        {
                            if (status.Status == X509ChainStatusFlags.PartialChain)
                            {
                                throw new CryptographicException(SR.Cryptography_Cms_IncompleteCertChain);
                            }
                        }
                    }

                    X509ChainElementCollection elements = chain.ChainElements;
                    int count = elements.Count;
                    int last  = count - 1;

                    if (last == 0)
                    {
                        // If there's always one cert treat it as EE, not root.
                        last = -1;
                    }

                    for (int i = 0; i < count; i++)
                    {
                        X509Certificate2 cert = elements[i].Certificate;

                        if (i == last &&
                            IncludeOption == X509IncludeOption.ExcludeRoot &&
                            cert.SubjectName.RawData.AsSpan().SequenceEqual(cert.IssuerName.RawData))
                        {
                            break;
                        }

                        certs.Add(cert);
                    }
                }
            }

            chainCerts = certs;
            return(newSignerInfo);
        }