Beispiel #1
0
        internal void Decode(ReadOnlyMemory <byte> encodedMessage)
        {
            AsnValueReader reader = new AsnValueReader(encodedMessage.Span, AsnEncodingRules.BER);

            // Windows (and thus NetFx) reads the leading data and ignores extra.
            // So use the Decode overload which doesn't throw on extra data.
            ContentInfoAsn.Decode(
                ref reader,
                encodedMessage,
                out ContentInfoAsn contentInfo);

            if (contentInfo.ContentType != Oids.Pkcs7Signed)
            {
                throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType);
            }

            // Hold a copy of the SignedData memory so we are protected against memory reuse by the caller.
            _heldData        = contentInfo.Content.ToArray();
            _signedData      = SignedDataAsn.Decode(_heldData, AsnEncodingRules.BER);
            _contentType     = _signedData.EncapContentInfo.ContentType;
            _hasPkcs7Content = false;

            if (!Detached)
            {
                ReadOnlyMemory <byte>?content = _signedData.EncapContentInfo.Content;
                ReadOnlyMemory <byte> contentValue;

                if (content.HasValue)
                {
                    contentValue = GetContent(content.Value, _contentType);
                    // If no OCTET STRING was stripped off, we have PKCS7 interop concerns.
                    _hasPkcs7Content = content.Value.Length == contentValue.Length;
                }
                else
                {
                    contentValue = ReadOnlyMemory <byte> .Empty;
                }

                // This is in _heldData, so we don't need a defensive copy.
                _heldContent = contentValue;

                // The ContentInfo object/property DOES need a defensive copy, because
                // a) it is mutable by the user, and
                // b) it is no longer authoritative
                //
                // (and c: it takes a byte[] and we have a ReadOnlyMemory<byte>)
                ContentInfo = new ContentInfo(new Oid(_contentType), contentValue.ToArray());
            }
            else
            {
                // Hold a defensive copy of the content bytes, (Windows/NetFx compat)
                _heldContent = ContentInfo.Content.CloneByteArray();
            }

            Version  = _signedData.Version;
            _hasData = true;
        }
Beispiel #2
0
        private void WithSelfInfo(WithSelfInfoDelegate action)
        {
            if (_parentSignerInfo == null)
            {
                int myIdx = _document.SignerInfos.FindIndexForSigner(this);

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

                ref SignedDataAsn signedData = ref _document.GetRawData();
                ref SignerInfoAsn mySigner   = ref signedData.SignerInfos[myIdx];
        public void Decode(byte[] encodedMessage)
        {
            if (encodedMessage == null)
            {
                throw new ArgumentNullException(nameof(encodedMessage));
            }

            // Windows (and thus NetFx) reads the leading data and ignores extra.
            // The deserializer will complain if too much data is given, so use the reader
            // to ask how much we want to deserialize.
            AsnReader             reader     = new AsnReader(encodedMessage, AsnEncodingRules.BER);
            ReadOnlyMemory <byte> cmsSegment = reader.GetEncodedValue();

            ContentInfoAsn contentInfo = AsnSerializer.Deserialize <ContentInfoAsn>(cmsSegment, AsnEncodingRules.BER);

            if (contentInfo.ContentType != Oids.Pkcs7Signed)
            {
                throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType);
            }

            // Hold a copy of the SignedData memory so we are protected against memory reuse by the caller.
            _heldData    = contentInfo.Content.ToArray();
            _signedData  = AsnSerializer.Deserialize <SignedDataAsn>(_heldData, AsnEncodingRules.BER);
            _contentType = _signedData.EncapContentInfo.ContentType;

            if (!Detached)
            {
                ReadOnlyMemory <byte>?content = _signedData.EncapContentInfo.Content;

                // This is in _heldData, so we don't need a defensive copy.
                _heldContent = content ?? ReadOnlyMemory <byte> .Empty;

                // The ContentInfo object/property DOES need a defensive copy, because
                // a) it is mutable by the user, and
                // b) it is no longer authoritative
                //
                // (and c: it takes a byte[] and we have a ReadOnlyMemory<byte>)
                ContentInfo = new ContentInfo(new Oid(_contentType), _heldContent.Value.ToArray());
            }
            else
            {
                // Hold a defensive copy of the content bytes, (Windows/NetFx compat)
                _heldContent = ContentInfo.Content.CloneByteArray();
            }

            Version  = _signedData.Version;
            _hasData = true;
        }
Beispiel #4
0
        public byte[] Encode()
        {
            if (!_hasData)
            {
                throw new InvalidOperationException(SR.Cryptography_Cms_MessageNotSigned);
            }

            try
            {
                using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
                {
                    _signedData.Encode(writer);
                    return(PkcsHelpers.EncodeContentInfo(writer.Encode(), Oids.Pkcs7Signed));
                }
            }
            catch (CryptographicException) when(!Detached)
            {
                // If we can't write the contents back out then the most likely culprit is an
                // indefinite length encoding in the content field.  To preserve as much input data
                // as possible while still maintaining our expectations of sorting any SET OF values,
                // do the following:
                // * Write the DER normalized version of the SignedData in detached mode.
                // * BER-decode that structure
                // * Copy the content field over
                // * BER-write the modified structure.

                SignedDataAsn copy = _signedData;

                copy.EncapContentInfo.Content = null;
                Debug.Assert(_signedData.EncapContentInfo.Content != null);

                using (AsnWriter detachedWriter = new AsnWriter(AsnEncodingRules.DER))
                {
                    copy.Encode(detachedWriter);
                    copy = SignedDataAsn.Decode(detachedWriter.Encode(), AsnEncodingRules.BER);
                }

                copy.EncapContentInfo.Content = _signedData.EncapContentInfo.Content;

                using (AsnWriter attachedWriter = new AsnWriter(AsnEncodingRules.BER))
                {
                    copy.Encode(attachedWriter);
                    return(PkcsHelpers.EncodeContentInfo(attachedWriter.Encode(), Oids.Pkcs7Signed));
                }
            }
        }
Beispiel #5
0
        internal void Decode(ReadOnlyMemory <byte> encodedMessage)
        {
            // Windows (and thus NetFx) reads the leading data and ignores extra.
            // So use the Deserialize overload which doesn't throw on extra data.
            ContentInfoAsn contentInfo = AsnSerializer.Deserialize <ContentInfoAsn>(
                encodedMessage,
                AsnEncodingRules.BER,
                out int bytesRead);

            if (contentInfo.ContentType != Oids.Pkcs7Signed)
            {
                throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType);
            }

            // Hold a copy of the SignedData memory so we are protected against memory reuse by the caller.
            _heldData    = contentInfo.Content.ToArray();
            _signedData  = AsnSerializer.Deserialize <SignedDataAsn>(_heldData, AsnEncodingRules.BER);
            _contentType = _signedData.EncapContentInfo.ContentType;

            if (!Detached)
            {
                ReadOnlyMemory <byte>?content = _signedData.EncapContentInfo.Content;

                // This is in _heldData, so we don't need a defensive copy.
                _heldContent = content ?? ReadOnlyMemory <byte> .Empty;

                // The ContentInfo object/property DOES need a defensive copy, because
                // a) it is mutable by the user, and
                // b) it is no longer authoritative
                //
                // (and c: it takes a byte[] and we have a ReadOnlyMemory<byte>)
                ContentInfo = new ContentInfo(new Oid(_contentType), _heldContent.Value.ToArray());
            }
            else
            {
                // Hold a defensive copy of the content bytes, (Windows/NetFx compat)
                _heldContent = ContentInfo.Content.CloneByteArray();
            }

            Version  = _signedData.Version;
            _hasData = true;
        }
Beispiel #6
0
        public void Decode(ReadOnlySpan <byte> encodedMessage)
        {
            // Hold a copy of the SignedData memory so we are protected against memory reuse by the caller.
            _heldData        = CopyContent(encodedMessage);
            _signedData      = SignedDataAsn.Decode(_heldData, AsnEncodingRules.BER);
            _contentType     = _signedData.EncapContentInfo.ContentType;
            _hasPkcs7Content = false;

            if (!Detached)
            {
                ReadOnlyMemory <byte>?content = _signedData.EncapContentInfo.Content;
                ReadOnlyMemory <byte> contentValue;

                if (content.HasValue)
                {
                    contentValue = GetContent(content.Value, _contentType);
                    // If no OCTET STRING was stripped off, we have PKCS7 interop concerns.
                    _hasPkcs7Content = content.Value.Length == contentValue.Length;
                }
                else
                {
                    contentValue = ReadOnlyMemory <byte> .Empty;
                }

                // This is in _heldData, so we don't need a defensive copy.
                _heldContent = contentValue;

                // The ContentInfo object/property DOES need a defensive copy, because
                // a) it is mutable by the user, and
                // b) it is no longer authoritative
                //
                // (and c: it takes a byte[] and we have a ReadOnlyMemory<byte>)
                ContentInfo = new ContentInfo(new Oid(_contentType), contentValue.ToArray());
            }
            else
            {
                // Hold a defensive copy of the content bytes, (Windows/NetFx compat)
                _heldContent = ContentInfo.Content.CloneByteArray();
            }

            Version  = _signedData.Version;
            _hasData = true;
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 (_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 #8
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 #9
0
        public static Pkcs12Info Decode(
            ReadOnlyMemory <byte> encodedBytes,
            out int bytesConsumed,
            bool skipCopy = false)
        {
            AsnReader reader = new AsnReader(encodedBytes, AsnEncodingRules.BER);

            // Trim it to the first value
            encodedBytes = reader.PeekEncodedValue();

            ReadOnlyMemory <byte> maybeCopy = skipCopy ? encodedBytes : encodedBytes.ToArray();
            PfxAsn pfx = PfxAsn.Decode(maybeCopy, AsnEncodingRules.BER);

            // https://tools.ietf.org/html/rfc7292#section-4 only defines version 3.
            if (pfx.Version != 3)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            ReadOnlyMemory <byte> authSafeBytes = ReadOnlyMemory <byte> .Empty;
            Pkcs12IntegrityMode   mode          = Pkcs12IntegrityMode.Unknown;

            if (pfx.AuthSafe.ContentType == Oids.Pkcs7Data)
            {
                authSafeBytes = PkcsHelpers.DecodeOctetStringAsMemory(pfx.AuthSafe.Content);

                if (pfx.MacData.HasValue)
                {
                    mode = Pkcs12IntegrityMode.Password;
                }
                else
                {
                    mode = Pkcs12IntegrityMode.None;
                }
            }
            else if (pfx.AuthSafe.ContentType == Oids.Pkcs7Signed)
            {
                SignedDataAsn signedData = SignedDataAsn.Decode(pfx.AuthSafe.Content, AsnEncodingRules.BER);

                mode = Pkcs12IntegrityMode.PublicKey;

                if (signedData.EncapContentInfo.ContentType == Oids.Pkcs7Data)
                {
                    authSafeBytes = signedData.EncapContentInfo.Content.GetValueOrDefault();
                }

                if (pfx.MacData.HasValue)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }
            }

            if (mode == Pkcs12IntegrityMode.Unknown)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            List <ContentInfoAsn> authSafeData   = new List <ContentInfoAsn>();
            AsnReader             authSafeReader = new AsnReader(authSafeBytes, AsnEncodingRules.BER);
            AsnReader             sequenceReader = authSafeReader.ReadSequence();

            authSafeReader.ThrowIfNotEmpty();
            while (sequenceReader.HasData)
            {
                ContentInfoAsn.Decode(sequenceReader, out ContentInfoAsn contentInfo);
                authSafeData.Add(contentInfo);
            }

            ReadOnlyCollection <Pkcs12SafeContents> authSafe;

            if (authSafeData.Count == 0)
            {
                authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(Array.Empty <Pkcs12SafeContents>());
            }
            else
            {
                Pkcs12SafeContents[] contentsArray = new Pkcs12SafeContents[authSafeData.Count];

                for (int i = 0; i < contentsArray.Length; i++)
                {
                    contentsArray[i] = new Pkcs12SafeContents(authSafeData[i]);
                }

                authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(contentsArray);
            }

            bytesConsumed = encodedBytes.Length;

            return(new Pkcs12Info
            {
                AuthenticatedSafe = authSafe,
                IntegrityMode = mode,
                _decoded = pfx,
                _authSafeContents = authSafeBytes,
            });
        }