Example #1
0
        /// <summary>
        ///   Locates the contents range for the encoded value at the beginning of the
        ///   <paramref name="source"/> buffer using the specified encoding rules.
        /// </summary>
        /// <param name="source">The buffer containing encoded data.</param>
        /// <param name="ruleSet">The encoding constraints to use when interpreting the data.</param>
        /// <param name="contentOffset">
        ///   When this method returns, the offset of the content payload relative to the start of
        ///   <paramref name="source"/>.
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <param name="contentLength">
        ///   When this method returns, the number of bytes in the content payload (which may be 0).
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <param name="bytesConsumed">
        ///   When this method returns, the total number of bytes for the encoded value.
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <returns>
        ///   The tag identifying the content.
        /// </returns>
        /// <remarks>
        ///   <para>
        ///     This method performs very little validation on the contents.
        ///     If the encoded value uses a definite length, the contents are not inspected at all.
        ///     If the encoded value uses an indefinite length, the contents are only inspected
        ///     as necessary to determine the location of the relevant end-of-contents marker.
        ///   </para>
        ///   <para>
        ///     When the encoded value uses an indefinite length, the <paramref name="bytesConsumed"/>
        ///     value will be larger than the sum of <paramref name="contentOffset"/> and
        ///     <paramref name="contentLength"/> to account for the end-of-contents marker.
        ///   </para>
        /// </remarks>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="ruleSet"/> is not defined.
        /// </exception>
        /// <exception cref="AsnContentException">
        ///   <paramref name="source"/> does not represent a value encoded under the specified
        ///   encoding rules.
        /// </exception>
        public static Asn1Tag ReadEncodedValue(
            ReadOnlySpan <byte> source,
            AsnEncodingRules ruleSet,
            out int contentOffset,
            out int contentLength,
            out int bytesConsumed)
        {
            CheckEncodingRules(ruleSet);

            Asn1Tag tag           = Asn1Tag.Decode(source, out int tagLength);
            int?    encodedLength = ReadLength(source.Slice(tagLength), ruleSet, out int lengthLength);
            int     headerLength  = tagLength + lengthLength;

            LengthValidity validity = ValidateLength(
                source.Slice(headerLength),
                ruleSet,
                tag,
                encodedLength,
                out int len,
                out int consumed);

            if (validity == LengthValidity.Valid)
            {
                contentOffset = headerLength;
                contentLength = len;
                bytesConsumed = headerLength + consumed;
                return(tag);
            }

            throw GetValidityException(validity);
        }
Example #2
0
        private static AsnContentException GetValidityException(LengthValidity validity)
        {
            Debug.Assert(validity != LengthValidity.Valid);

            switch (validity)
            {
            case LengthValidity.CerRequiresIndefinite:
                return(new AsnContentException(SR.ContentException_CerRequiresIndefiniteLength));

            case LengthValidity.LengthExceedsInput:
                return(new AsnContentException(SR.ContentException_LengthExceedsPayload));

            case LengthValidity.PrimitiveEncodingRequiresDefinite:
                return(new AsnContentException());

            default:
                Debug.Fail($"No handler for validity {validity}.");
                goto case LengthValidity.PrimitiveEncodingRequiresDefinite;
            }
        }
Example #3
0
        /// <summary>
        ///   Attempts locate the contents range for the encoded value at the beginning of the
        ///   <paramref name="source"/> buffer using the specified encoding rules.
        /// </summary>
        /// <param name="source">The buffer containing encoded data.</param>
        /// <param name="ruleSet">The encoding constraints to use when interpreting the data.</param>
        /// <param name="tag">
        ///   When this method returns, the tag identifying the content.
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <param name="contentOffset">
        ///   When this method returns, the offset of the content payload relative to the start of
        ///   <paramref name="source"/>.
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <param name="contentLength">
        ///   When this method returns, the number of bytes in the content payload (which may be 0).
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <param name="bytesConsumed">
        ///   When this method returns, the total number of bytes for the encoded value.
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <returns>
        ///   <see langword="true" /> if <paramref name="source"/> represents a valid structural
        ///   encoding for the specified encoding rules; otherwise, <see langword="false"/>.
        /// </returns>
        /// <remarks>
        ///   <para>
        ///     This method performs very little validation on the contents.
        ///     If the encoded value uses a definite length, the contents are not inspected at all.
        ///     If the encoded value uses an indefinite length, the contents are only inspected
        ///     as necessary to determine the location of the relevant end-of-contents marker.
        ///   </para>
        ///   <para>
        ///     When the encoded value uses an indefinite length, the <paramref name="bytesConsumed"/>
        ///     value will be larger than the sum of <paramref name="contentOffset"/> and
        ///     <paramref name="contentLength"/> to account for the end-of-contents marker.
        ///   </para>
        /// </remarks>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="ruleSet"/> is not defined.
        /// </exception>
        public static bool TryReadEncodedValue(
            ReadOnlySpan <byte> source,
            AsnEncodingRules ruleSet,
            out Asn1Tag tag,
            out int contentOffset,
            out int contentLength,
            out int bytesConsumed)
        {
            CheckEncodingRules(ruleSet);

            if (Asn1Tag.TryDecode(source, out Asn1Tag localTag, out int tagLength) &&
                TryReadLength(source.Slice(tagLength), ruleSet, out int?encodedLength, out int lengthLength))
            {
                int headerLength = tagLength + lengthLength;

                LengthValidity validity = ValidateLength(
                    source.Slice(headerLength),
                    ruleSet,
                    localTag,
                    encodedLength,
                    out int len,
                    out int consumed);

                if (validity == LengthValidity.Valid)
                {
                    tag           = localTag;
                    contentOffset = headerLength;
                    contentLength = len;
                    bytesConsumed = headerLength + consumed;
                    return(true);
                }
            }

            tag           = default;
            contentOffset = contentLength = bytesConsumed = 0;
            return(false);
        }