Exemplo n.º 1
0
        /// <summary>
        ///   Begin writing a Sequence with a specified tag.
        /// </summary>
        /// <param name="tag">The tag to write, or <see langword="null"/> for the default tag (Universal 16).</param>
        /// <returns>
        ///   A disposable value which will automatically call <see cref="PopSequence"/>.
        /// </returns>
        /// <exception cref="ArgumentException">
        ///   <paramref name="tag"/>.<see cref="Asn1Tag.TagClass"/> is
        ///   <see cref="TagClass.Universal"/>, but
        ///   <paramref name="tag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
        ///   the method.
        /// </exception>
        /// <seealso cref="PopSequence"/>
        public Scope PushSequence(Asn1Tag?tag = null)
        {
            CheckUniversalTag(tag, UniversalTagNumber.Sequence);

            // Assert the constructed flag, in case it wasn't.
            return(PushSequenceCore(tag?.AsConstructed() ?? Asn1Tag.Sequence));
        }
        /// <summary>
        ///   Indicate that the open Set-Of with the specified tag is closed,
        ///   returning the writer to the parent context.
        /// </summary>
        /// <param name="tag">The tag to write, or <see langword="null"/> for the default tag (Universal 17).</param>
        /// <remarks>
        ///   In <see cref="AsnEncodingRules.CER"/> and <see cref="AsnEncodingRules.DER"/> modes
        ///   the writer will sort the Set-Of elements when the tag is closed.
        /// </remarks>
        /// <exception cref="ArgumentException">
        ///   <paramref name="tag"/>.<see cref="Asn1Tag.TagClass"/> is
        ///   <see cref="TagClass.Universal"/>, but
        ///   <paramref name="tag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
        ///   the method.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///   the writer is not currently positioned within a Set-Of with the specified tag.
        /// </exception>
        /// <seealso cref="PushSetOf"/>
        public void PopSetOf(Asn1Tag?tag = null)
        {
            CheckUniversalTag(tag, UniversalTagNumber.SetOf);

            // Assert the constructed flag, in case it wasn't.
            PopSetOfCore(tag?.AsConstructed() ?? Asn1Tag.SetOf);
        }
Exemplo n.º 3
0
        /// <summary>
        ///   Indicate that the open Sequence with the specified tag is closed,
        ///   returning the writer to the parent context.
        /// </summary>
        /// <param name="tag">The tag to write, or <see langword="null"/> for the default tag (Universal 16).</param>
        /// <exception cref="ArgumentException">
        ///   <paramref name="tag"/>.<see cref="Asn1Tag.TagClass"/> is
        ///   <see cref="TagClass.Universal"/>, but
        ///   <paramref name="tag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
        ///   the method.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///   the writer is not currently positioned within a Sequence with the specified tag.
        /// </exception>
        /// <seealso cref="PushSequence"/>
        public void PopSequence(Asn1Tag?tag = null)
        {
            // PopSequence shouldn't be used to pop a SetOf.
            CheckUniversalTag(tag, UniversalTagNumber.Sequence);

            // Assert the constructed flag, in case it wasn't.
            PopSequenceCore(tag?.AsConstructed() ?? Asn1Tag.Sequence);
        }
        /// <summary>
        ///   Begin writing an Octet String value with a specified tag.
        /// </summary>
        /// <returns>
        ///   A disposable value which will automatically call <see cref="PopOctetString"/>.
        /// </returns>
        /// <remarks>
        ///   This method is just an accelerator for writing an Octet String value where the
        ///   contents are also ASN.1 data encoded under the same encoding system.
        ///   When <see cref="PopOctetString"/> is called the entire nested contents are
        ///   normalized as a single Octet String value, encoded correctly for the current encoding
        ///   rules.
        ///   This method does not necessarily create a Constructed encoding, and it is not invalid to
        ///   write values other than Octet String inside this Push/Pop.
        /// </remarks>
        /// <param name="tag">The tag to write, or <see langword="null"/> for the default tag (Universal 4).</param>
        /// <seealso cref="PopOctetString"/>
        public Scope PushOctetString(Asn1Tag?tag = null)
        {
            CheckUniversalTag(tag, UniversalTagNumber.OctetString);

            return(PushTag(
                       tag?.AsConstructed() ?? Asn1Tag.ConstructedOctetString,
                       UniversalTagNumber.OctetString));
        }
Exemplo n.º 5
0
        // T-REC-X.690-201508 sec 9.2, 8.6
        private void WriteConstructedCerBitString(Asn1Tag tag, ReadOnlySpan <byte> payload, int unusedBitCount)
        {
            const int MaxCERSegmentSize = AsnReader.MaxCERSegmentSize;
            // Every segment has an "unused bit count" byte.
            const int MaxCERContentSize = MaxCERSegmentSize - 1;

            Debug.Assert(payload.Length > MaxCERContentSize);

            int expectedSize = DetermineCerBitStringTotalLength(tag, payload.Length);

            EnsureWriteCapacity(expectedSize);
            int savedOffset = _offset;

            WriteTag(tag.AsConstructed());
            // T-REC-X.690-201508 sec 9.1
            // Constructed CER uses the indefinite form.
            WriteLength(-1);

            byte[] ensureNoExtraCopy = _buffer;

            ReadOnlySpan <byte> remainingData = payload;
            Span <byte>         dest;
            Asn1Tag             primitiveBitString = Asn1Tag.PrimitiveBitString;

            while (remainingData.Length > MaxCERContentSize)
            {
                // T-REC-X.690-201508 sec 8.6.4.1
                WriteTag(primitiveBitString);
                WriteLength(MaxCERSegmentSize);
                // 0 unused bits in this segment.
                _buffer[_offset] = 0;
                _offset++;

                dest = _buffer.AsSpan(_offset);
                remainingData.Slice(0, MaxCERContentSize).CopyTo(dest);

                remainingData = remainingData.Slice(MaxCERContentSize);
                _offset      += MaxCERContentSize;
            }

            WriteTag(primitiveBitString);
            WriteLength(remainingData.Length + 1);

            _buffer[_offset] = (byte)unusedBitCount;
            _offset++;

            dest = _buffer.AsSpan(_offset);
            remainingData.CopyTo(dest);
            _offset += remainingData.Length;

            WriteEndOfContents();

            Debug.Assert(_offset - savedOffset == expectedSize, $"expected size was {expectedSize}, actual was {_offset - savedOffset}");
            Debug.Assert(_buffer == ensureNoExtraCopy, $"_buffer was replaced during {nameof(WriteConstructedCerBitString)}");
        }
 /// <summary>
 ///   Indicate that the open Octet String with the tag UNIVERSAL 4 is closed,
 ///   returning the writer to the parent context.
 /// </summary>
 /// <param name="tag">The tag to write, or <see langword="null"/> for the default tag (Universal 4).</param>
 /// <remarks>
 ///   In <see cref="AsnEncodingRules.BER"/> and <see cref="AsnEncodingRules.DER"/> modes
 ///   the encoded contents will remain in a single primitive Octet String.
 ///   In <see cref="AsnEncodingRules.CER"/> mode the contents will be broken up into
 ///   multiple segments, when required.
 /// </remarks>
 /// <exception cref="ArgumentException">
 ///   <paramref name="tag"/>.<see cref="Asn1Tag.TagClass"/> is
 ///   <see cref="TagClass.Universal"/>, but
 ///   <paramref name="tag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
 ///   the method.
 /// </exception>
 /// <exception cref="InvalidOperationException">
 ///   the writer is not currently positioned within an Octet String with the specified tag.
 /// </exception>
 public void PopOctetString(Asn1Tag?tag = default)
 {
     CheckUniversalTag(tag, UniversalTagNumber.OctetString);
     PopTag(tag?.AsConstructed() ?? Asn1Tag.ConstructedOctetString, UniversalTagNumber.OctetString);
 }
        // T-REC-X.690-201508 sec 9.2, 8.7
        private void WriteConstructedCerOctetString(Asn1Tag tag, ReadOnlySpan <byte> payload)
        {
            const int MaxCERSegmentSize = AsnReader.MaxCERSegmentSize;

            Debug.Assert(payload.Length > MaxCERSegmentSize);

            WriteTag(tag.AsConstructed());
            WriteLength(-1);

            int fullSegments = Math.DivRem(payload.Length, MaxCERSegmentSize, out int lastSegmentSize);

            // The tag size is 1 byte.
            // The length will always be encoded as 82 03 E8 (3 bytes)
            // And 1000 content octets (by T-REC-X.690-201508 sec 9.2)
            const int FullSegmentEncodedSize = 1004;

            Debug.Assert(
                FullSegmentEncodedSize == 1 + 1 + MaxCERSegmentSize + GetEncodedLengthSubsequentByteCount(MaxCERSegmentSize));

            int remainingEncodedSize;

            if (lastSegmentSize == 0)
            {
                remainingEncodedSize = 0;
            }
            else
            {
                // One byte of tag, and minimum one byte of length.
                remainingEncodedSize = 2 + lastSegmentSize + GetEncodedLengthSubsequentByteCount(lastSegmentSize);
            }

            // Reduce the number of copies by pre-calculating the size.
            // +2 for End-Of-Contents
            int expectedSize = fullSegments * FullSegmentEncodedSize + remainingEncodedSize + 2;

            EnsureWriteCapacity(expectedSize);

            byte[] ensureNoExtraCopy = _buffer;
            int    savedOffset       = _offset;

            ReadOnlySpan <byte> remainingData = payload;
            Span <byte>         dest;
            Asn1Tag             primitiveOctetString = Asn1Tag.PrimitiveOctetString;

            while (remainingData.Length > MaxCERSegmentSize)
            {
                // T-REC-X.690-201508 sec 8.7.3.2-note2
                WriteTag(primitiveOctetString);
                WriteLength(MaxCERSegmentSize);

                dest = _buffer.AsSpan(_offset);
                remainingData.Slice(0, MaxCERSegmentSize).CopyTo(dest);

                _offset      += MaxCERSegmentSize;
                remainingData = remainingData.Slice(MaxCERSegmentSize);
            }

            WriteTag(primitiveOctetString);
            WriteLength(remainingData.Length);
            dest = _buffer.AsSpan(_offset);
            remainingData.CopyTo(dest);
            _offset += remainingData.Length;

            WriteEndOfContents();

            Debug.Assert(_offset - savedOffset == expectedSize, $"expected size was {expectedSize}, actual was {_offset - savedOffset}");
            Debug.Assert(_buffer == ensureNoExtraCopy, $"_buffer was replaced during {nameof(WriteConstructedCerOctetString)}");
        }