Example #1
0
        private ReadOnlyMemory <byte> GetIntegerContents(
            Asn1Tag expectedTag,
            UniversalTagNumber tagNumber,
            out int headerLength)
        {
            Asn1Tag tag = ReadTagAndLength(out int?length, out headerLength);

            CheckExpectedTag(tag, expectedTag, tagNumber);

            // T-REC-X.690-201508 sec 8.3.1
            if (tag.IsConstructed || length < 1)
            {
                throw new CryptographicException(SR.Resource("Cryptography_Der_Invalid_Encoding"));
            }

            // Slice first so that an out of bounds value triggers a CryptographicException.
            ReadOnlyMemory <byte> contents    = Slice(_data, headerLength, length.Value);
            ReadOnlySpan <byte>   contentSpan = contents.Span;

            // T-REC-X.690-201508 sec 8.3.2
            if (contents.Length > 1)
            {
                ushort       bigEndianValue = (ushort)(contentSpan[0] << 8 | contentSpan[1]);
                const ushort RedundancyMask = 0b1111_1111_1000_0000;
                ushort       masked         = (ushort)(bigEndianValue & RedundancyMask);

                // If the first 9 bits are all 0 or are all 1, the value is invalid.
                if (masked == 0 || masked == RedundancyMask)
                {
                    throw new CryptographicException(SR.Resource("Cryptography_Der_Invalid_Encoding"));
                }
            }

            return(contents);
        }
Example #2
0
        /// <summary>
        ///   Write the provided string using the specified encoding type using the specified
        ///   tag corresponding to the encoding type.
        /// </summary>
        /// <param name="tag">The tag to write.</param>
        /// <param name="encodingType">
        ///   The <see cref="UniversalTagNumber"/> corresponding to the encoding to use.
        /// </param>
        /// <param name="str">The string to write.</param>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="encodingType"/> is not a restricted character string encoding type --OR--
        ///   <paramref name="encodingType"/> is a restricted character string encoding type that is not
        ///   currently supported by this method
        /// </exception>
        /// <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="ObjectDisposedException">The writer has been Disposed.</exception>
        public void WriteCharacterString(Asn1Tag tag, UniversalTagNumber encodingType, ReadOnlySpan <char> str)
        {
            CheckUniversalTag(tag, encodingType);

            Text.Encoding encoding = AsnCharacterStringEncodings.GetEncoding(encodingType);
            this.WriteCharacterStringCore(tag, encoding, str);
        }
        private bool TryReadPrimitiveOctetStringBytes(
            Asn1Tag expectedTag,
            out Asn1Tag actualTag,
            out int?contentLength,
            out int headerLength,
            out ReadOnlySpan <byte> contents,
            UniversalTagNumber universalTagNumber = UniversalTagNumber.OctetString)
        {
            actualTag = ReadTagAndLength(out contentLength, out headerLength);
            CheckExpectedTag(actualTag, expectedTag, universalTagNumber);

            if (actualTag.IsConstructed)
            {
                if (RuleSet == AsnEncodingRules.DER)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }

                contents = default;
                return(false);
            }

            Debug.Assert(contentLength.HasValue);
            ReadOnlySpan <byte> encodedValue = Slice(_data, headerLength, contentLength.Value);

            if (RuleSet == AsnEncodingRules.CER && encodedValue.Length > MaxCERSegmentSize)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            contents = encodedValue;
            return(true);
        }
Example #4
0
        private static ReadOnlySpan <byte> GetPrimitiveContentSpan(
            ReadOnlySpan <byte> source,
            AsnEncodingRules ruleSet,
            Asn1Tag expectedTag,
            UniversalTagNumber tagNumber,
            out int bytesConsumed)
        {
            CheckEncodingRules(ruleSet);

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

            // Get caller(-of-my-caller) errors out of the way, first.
            CheckExpectedTag(localTag, expectedTag, tagNumber);

            // T-REC-X.690-201508 sec 8.1.3.2 says primitive encodings must use a definite form,
            // and the caller says they only want primitive values.
            if (localTag.IsConstructed)
            {
                throw new AsnContentException(
                          SR.Format(SR.ContentException_PrimitiveEncodingRequired, tagNumber));
            }

            if (encodedLength == null)
            {
                throw new AsnContentException();
            }

            ReadOnlySpan <byte> ret = Slice(source, headerLength, encodedLength.Value);

            bytesConsumed = headerLength + ret.Length;
            return(ret);
        }
        /// <summary>
        ///   Write the provided string using the specified encoding type using the specified
        ///   tag corresponding to the encoding type.
        /// </summary>
        /// <param name="encodingType">
        ///   One of the enumeration values representing the encoding to use.
        /// </param>
        /// <param name="str">The string to write.</param>
        /// <param name="tag">
        ///   The tag to write, or <see langword="null"/> for the universal tag that is appropriate to
        ///   the requested encoding type.
        /// </param>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="encodingType"/> is not a restricted character string encoding type.
        ///
        ///   -or-
        ///
        ///   <paramref name="encodingType"/> is a restricted character string encoding type that is not
        ///   currently supported by this method.
        /// </exception>
        /// <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>
        public void WriteCharacterString(UniversalTagNumber encodingType, ReadOnlySpan <char> str, Asn1Tag?tag = null)
        {
            CheckUniversalTag(tag, encodingType);

            Text.Encoding encoding = AsnCharacterStringEncodings.GetEncoding(encodingType);
            WriteCharacterStringCore(tag ?? new Asn1Tag(encodingType), encoding, str);
        }
        /// <summary>
        ///   Attempts to get an unprocessed character string value from <paramref name="source"/> with a
        ///   specified tag under the specified encoding rules, if the value is contained in a single
        ///   (primitive) encoding.
        /// </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="expectedTag">
        ///   The tag to check for before reading.
        /// </param>
        /// <param name="value">
        ///   On success, receives a slice of the input buffer that corresponds to
        ///   the value of the Bit String.
        ///   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 the character string value has a primitive encoding;
        ///   otherwise, <see langword="false"/>.
        /// </returns>
        /// <remarks>
        ///   This method does not determine if the string used only characters defined by the encoding.
        /// </remarks>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="ruleSet"/> is not defined.
        /// </exception>
        /// <exception cref="AsnContentException">
        ///   the next value does not have the correct tag.
        ///
        ///   -or-
        ///
        ///   the length encoding is not valid under the current encoding rules.
        ///
        ///   -or-
        ///
        ///   the contents are not valid under the current encoding rules.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
        ///   <see cref="TagClass.Universal"/>, but
        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not a character
        ///   string tag type.
        /// </exception>
        /// <seealso cref="TryReadCharacterStringBytes"/>
        public static bool TryReadPrimitiveCharacterStringBytes(
            ReadOnlySpan <byte> source,
            AsnEncodingRules ruleSet,
            Asn1Tag expectedTag,
            out ReadOnlySpan <byte> value,
            out int bytesConsumed)
        {
            // This doesn't matter, except for universal tags. It's eventually used to check that
            // we're not expecting the wrong universal tag; but we'll remove the need for that by
            // IsCharacterStringEncodingType.
            UniversalTagNumber universalTagNumber = UniversalTagNumber.IA5String;

            if (expectedTag.TagClass == TagClass.Universal)
            {
                universalTagNumber = (UniversalTagNumber)expectedTag.TagValue;

                if (!IsCharacterStringEncodingType(universalTagNumber))
                {
                    throw new ArgumentException(SR.Argument_Tag_NotCharacterString, nameof(expectedTag));
                }
            }

            // T-REC-X.690-201508 sec 8.23.3, all character strings are encoded as octet strings.
            return(TryReadPrimitiveOctetStringCore(
                       source,
                       ruleSet,
                       expectedTag,
                       universalTagNumber,
                       contentLength: out _,
                       headerLength: out _,
                       out value,
                       out bytesConsumed));
        }
Example #7
0
        private void EncodeComponent(
            string oid,
            ReadOnlySpan <char> value,
            UniversalTagNumber stringEncodingType,
            [CallerArgumentExpression("value")] string?paramName = null)
        {
            _writer.Reset();

            using (_writer.PushSetOf())
                using (_writer.PushSequence())
                {
                    _writer.WriteObjectIdentifier(oid);

                    try
                    {
                        _writer.WriteCharacterString(stringEncodingType, value);
                    }
                    catch (EncoderFallbackException)
                    {
                        throw new ArgumentException(SR.Format(SR.Argument_Asn1_InvalidStringContents, stringEncodingType), paramName);
                    }
                }

            _encodedComponents.Add(_writer.Encode());
        }
Example #8
0
        internal static Text.Encoding GetEncoding(UniversalTagNumber encodingType)
        {
            switch (encodingType)
            {
            case UniversalTagNumber.UTF8String:
                return(s_utf8Encoding);

            case UniversalTagNumber.PrintableString:
                return(s_printableStringEncoding);

            case UniversalTagNumber.IA5String:
                return(s_ia5Encoding);

            case UniversalTagNumber.VisibleString:
                return(s_visibleStringEncoding);

            case UniversalTagNumber.BMPString:
                return(s_bmpEncoding);

            case UniversalTagNumber.T61String:
                return(s_t61Encoding);

            default:
                throw new ArgumentOutOfRangeException(nameof(encodingType), encodingType, null);
            }
        }
        internal static Text.Encoding GetEncoding(UniversalTagNumber encodingType)
        {
            switch (encodingType)
            {
            case UniversalTagNumber.UTF8String:
                return(Utf8Encoding);

            case UniversalTagNumber.NumericString:
                return(NumericStringEncoding);

            case UniversalTagNumber.PrintableString:
                return(PrintableStringEncoding);

            case UniversalTagNumber.IA5String:
                return(Ia5Encoding);

            case UniversalTagNumber.GeneralString:
                return(GeneralStringEncoding);

            case UniversalTagNumber.VisibleString:
                return(VisibleStringEncoding);

            case UniversalTagNumber.BMPString:
                return(BmpEncoding);

            case UniversalTagNumber.T61String:
                return(T61Encoding);

            default:
                throw new ArgumentOutOfRangeException(nameof(encodingType), encodingType, null);
            }
        }
Example #10
0
        internal string ReadCharacterString(UniversalTagNumber encodingType, Asn1Tag?expectedTag = default)
        {
            string ret = AsnDecoder.ReadCharacterString(_span, _ruleSet, encodingType, out int consumed, expectedTag);

            _span = _span.Slice(consumed);
            return(ret);
        }
Example #11
0
        private bool TryReadSignedInteger(
            int sizeLimit,
            Asn1Tag expectedTag,
            UniversalTagNumber tagNumber,
            out long value)
        {
            Debug.Assert(sizeLimit <= sizeof(long));

            ReadOnlyMemory <byte> contents = GetIntegerContents(expectedTag, tagNumber, out int headerLength);

            if (contents.Length > sizeLimit)
            {
                value = 0;
                return(false);
            }

            ReadOnlySpan <byte> contentSpan = contents.Span;

            bool isNegative = (contentSpan[0] & 0x80) != 0;
            long accum      = isNegative ? -1 : 0;

            for (int i = 0; i < contents.Length; i++)
            {
                accum <<= 8;
                accum  |= contentSpan[i];
            }

            _data = _data.Slice(headerLength + contents.Length);
            value = accum;
            return(true);
        }
        private static ReadOnlySpan <byte> GetOctetStringContents(
            ReadOnlySpan <byte> source,
            AsnEncodingRules ruleSet,
            Asn1Tag expectedTag,
            UniversalTagNumber universalTagNumber,
            out int bytesConsumed,
            ref byte[]?rented,
            Span <byte> tmpSpace = default)
        {
            Debug.Assert(rented == null);

            if (TryReadPrimitiveOctetStringCore(
                    source,
                    ruleSet,
                    expectedTag,
                    universalTagNumber,
                    out int?contentLength,
                    out int headerLength,
                    out ReadOnlySpan <byte> contents,
                    out bytesConsumed))
            {
                return(contents);
            }

            // If we get here, the tag was appropriate, but the encoding was constructed.

            // Guaranteed long enough
            contents = source.Slice(headerLength);
            int tooBig = contentLength ?? SeekEndOfContents(contents, ruleSet);

            if (tmpSpace.Length > 0 && tooBig > tmpSpace.Length)
            {
                bool isIndefinite = contentLength == null;
                tooBig = CountConstructedOctetString(contents, ruleSet, isIndefinite);
            }

            if (tooBig > tmpSpace.Length)
            {
                rented   = CryptoPool.Rent(tooBig);
                tmpSpace = rented;
            }

            if (TryCopyConstructedOctetStringContents(
                    Slice(source, headerLength, contentLength),
                    ruleSet,
                    tmpSpace,
                    contentLength == null,
                    out int bytesRead,
                    out int bytesWritten))
            {
                bytesConsumed = headerLength + bytesRead;
                return(tmpSpace.Slice(0, bytesWritten));
            }

            Debug.Fail("TryCopyConstructedOctetStringContents failed with a pre-allocated buffer");
            throw new AsnContentException();
        }
        /// <summary>
        ///   Write the provided string using the specified encoding type using the specified
        ///   tag corresponding to the encoding type.
        /// </summary>
        /// <param name="encodingType">
        ///   One of the enumeration values representing the encoding to use.
        /// </param>
        /// <param name="value">The string to write.</param>
        /// <param name="tag">
        ///   The tag to write, or <see langword="null"/> for the universal tag that is appropriate to
        ///   the requested encoding type.
        /// </param>
        /// <exception cref="ArgumentNullException"><paramref name="value"/> is <see langword="null"/></exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="encodingType"/> is not a restricted character string encoding type.
        ///
        ///   -or-
        ///
        ///   <paramref name="encodingType"/> is a restricted character string encoding type that is not
        ///   currently supported by this method.
        /// </exception>
        /// <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>
        public void WriteCharacterString(UniversalTagNumber encodingType, string value, Asn1Tag?tag = null)
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            WriteCharacterString(encodingType, value.AsSpan(), tag);
        }
 private static void WriteRdn(AsnWriter writer, string oid, string value, UniversalTagNumber valueType)
 {
     writer.PushSetOf();
     writer.PushSequence();
     writer.WriteObjectIdentifier(oid);
     writer.WriteCharacterString(valueType, value);
     writer.PopSequence();
     writer.PopSetOf();
 }
Example #15
0
        /// <summary>
        ///   Write the provided string using the specified encoding type using the specified
        ///   tag corresponding to the encoding type.
        /// </summary>
        /// <param name="tag">The tag to write.</param>
        /// <param name="encodingType">
        ///   The <see cref="UniversalTagNumber"/> corresponding to the encoding to use.
        /// </param>
        /// <param name="str">The string to write.</param>
        /// <exception cref="ArgumentNullException"><paramref name="str"/> is <c>null</c></exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="encodingType"/> is not a restricted character string encoding type --OR--
        ///   <paramref name="encodingType"/> is a restricted character string encoding type that is not
        ///   currently supported by this method
        /// </exception>
        /// <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="ObjectDisposedException">The writer has been Disposed.</exception>
        public void WriteCharacterString(Asn1Tag tag, UniversalTagNumber encodingType, string str)
        {
            if (str == null)
            {
                throw new ArgumentNullException(nameof(str));
            }

            WriteCharacterString(tag, encodingType, str.AsSpan());
        }
        /// <summary>
        /// Adds a Relative Distinguished Name attribute identified by an OID.
        /// </summary>
        /// <param name="oidValue">The OID of the attribute.</param>
        /// <param name="value">The value of the attribute.</param>
        /// <param name="stringEncodingType">
        /// The encoding type to use when encoding the <paramref name="value" />
        /// in to the attribute.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="oidValue" /> or <paramref name="value" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <para>
        ///   <paramref name="oidValue" /> is an empty string or not a valid OID.
        /// </para>
        /// <para>-or-</para>
        /// <para>
        ///   <paramref name="stringEncodingType" /> is not a type for character strings.
        /// </para>
        /// <para>-or-</para>
        /// <para>
        ///   <paramref name="value" /> is not encodable as defined by <paramref name="stringEncodingType" />.
        /// </para>
        /// </exception>
        public void Add(string oidValue, string value, UniversalTagNumber?stringEncodingType = null)
        {
            ArgumentNullException.ThrowIfNull(value);
            ArgumentException.ThrowIfNullOrEmpty(oidValue);

            UniversalTagNumber tag = GetAndValidateTagNumber(stringEncodingType);

            EncodeComponent(oidValue, value, tag);
        }
Example #17
0
 /// <summary>
 ///   Reads the next value as character string with the specified tag and
 ///   encoding type, copying the decoded value into a provided destination buffer.
 /// </summary>
 /// <param name="expectedTag">The tag to check for before reading.</param>
 /// <param name="encodingType">
 ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
 /// </param>
 /// <param name="destination">The buffer in which to write.</param>
 /// <param name="charsWritten">
 ///   On success, receives the number of chars written to <paramref name="destination"/>.
 /// </param>
 /// <returns>
 ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
 ///   length to receive the value, otherwise
 ///   <c>false</c> and the reader does not advance.
 /// </returns>
 /// <exception cref="ArgumentOutOfRangeException">
 ///   <paramref name="encodingType"/> is not a known character string type.
 /// </exception>
 /// <exception cref="CryptographicException">
 ///   the next value does not have the correct tag --OR--
 ///   the length encoding is not valid under the current encoding rules --OR--
 ///   the contents are not valid under the current encoding rules --OR--
 ///   the string did not successfully decode
 /// </exception>
 /// <exception cref="ArgumentException">
 ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
 ///   <see cref="TagClass.Universal"/>, but
 ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
 ///   <paramref name="encodingType"/>.
 /// </exception>
 /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
 /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,Span{byte},out int)"/>
 /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
 public bool TryCopyCharacterString(
     Asn1Tag expectedTag,
     UniversalTagNumber encodingType,
     Span <char> destination,
     out int charsWritten)
 {
     Text.Encoding encoding = AsnCharacterStringEncodings.GetEncoding(encodingType);
     return(TryCopyCharacterString(expectedTag, encodingType, encoding, destination, out charsWritten));
 }
Example #18
0
 /// <summary>
 ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
 ///   encoding type, returning the contents as an unprocessed <see cref="ReadOnlyMemory{T}"/>
 ///   over the original data.
 /// </summary>
 /// <param name="encodingType">
 ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
 /// </param>
 /// <param name="contents">
 ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
 ///   corresponding to the contents of the character string.
 /// </param>
 /// <returns>
 ///   <c>true</c> and advances the reader if the value had a primitive encoding,
 ///   <c>false</c> and does not advance the reader if it had a constructed encoding.
 /// </returns>
 /// <remarks>
 ///   This method does not determine if the string used only characters defined by the encoding.
 /// </remarks>
 /// <exception cref="ArgumentOutOfRangeException">
 ///   <paramref name="encodingType"/> is not a known character string type.
 /// </exception>
 /// <exception cref="CryptographicException">
 ///   the next value does not have the correct tag --OR--
 ///   the length encoding is not valid under the current encoding rules --OR--
 ///   the contents are not valid under the current encoding rules
 /// </exception>
 /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,Span{byte},out int)"/>
 public bool TryReadPrimitiveCharacterStringBytes(
     UniversalTagNumber encodingType,
     out ReadOnlyMemory <byte> contents)
 {
     return(TryReadPrimitiveCharacterStringBytes(
                new Asn1Tag(encodingType),
                encodingType,
                out contents));
 }
Example #19
0
        /// <summary>
        ///   Reads the next value as a character with a specified tag, returning the contents
        ///   as an unprocessed <see cref="ReadOnlyMemory{T}"/> over the original data.
        /// </summary>
        /// <param name="expectedTag">The tag to check for before reading.</param>
        /// <param name="encodingType">
        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
        /// </param>
        /// <param name="contents">
        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
        ///   corresponding to the value of the OCTET STRING.
        /// </param>
        /// <returns>
        ///   <c>true</c> and advances the reader if the OCTET STRING value had a primitive encoding,
        ///   <c>false</c> and does not advance the reader if it had a constructed encoding.
        /// </returns>
        /// <remarks>
        ///   This method does not determine if the string used only characters defined by the encoding.
        /// </remarks>
        /// <exception cref="CryptographicException">
        ///   the next value does not have the correct tag --OR--
        ///   the length encoding is not valid under the current encoding rules --OR--
        ///   the contents are not valid under the current encoding rules
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
        ///   <see cref="TagClass.Universal"/>, but
        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
        ///   <paramref name="encodingType"/>.
        /// </exception>
        /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,Span{byte},out int)"/>
        public bool TryReadPrimitiveCharacterStringBytes(
            Asn1Tag expectedTag,
            UniversalTagNumber encodingType,
            out ReadOnlyMemory <byte> contents)
        {
            CheckCharacterStringEncodingType(encodingType);

            // T-REC-X.690-201508 sec 8.23.3, all character strings are encoded as octet strings.
            return(TryReadPrimitiveOctetStringBytes(expectedTag, encodingType, out contents));
        }
Example #20
0
 /// <summary>
 ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
 ///   encoding type, copying the decoded value into a provided destination buffer.
 /// </summary>
 /// <param name="encodingType">
 ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
 /// </param>
 /// <param name="destination">The buffer in which to write.</param>
 /// <param name="charsWritten">
 ///   On success, receives the number of chars written to <paramref name="destination"/>.
 /// </param>
 /// <returns>
 ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
 ///   length to receive the value, otherwise
 ///   <c>false</c> and the reader does not advance.
 /// </returns>
 /// <exception cref="ArgumentOutOfRangeException">
 ///   <paramref name="encodingType"/> is not a known character string type.
 /// </exception>
 /// <exception cref="CryptographicException">
 ///   the next value does not have the correct tag --OR--
 ///   the length encoding is not valid under the current encoding rules --OR--
 ///   the contents are not valid under the current encoding rules --OR--
 ///   the string did not successfully decode
 /// </exception>
 /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
 /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
 /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,ArraySegment{byte},out int)"/>
 /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,ArraySegment{char},out int)"/>
 public bool TryCopyCharacterString(
     UniversalTagNumber encodingType,
     ArraySegment <char> destination,
     out int charsWritten)
 {
     return(TryCopyCharacterString(
                new Asn1Tag(encodingType),
                encodingType,
                destination.AsSpan(),
                out charsWritten));
 }
Example #21
0
 /// <summary>
 ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
 ///   encoding type, copying the value into a provided destination buffer.
 /// </summary>
 /// <param name="encodingType">
 ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
 /// </param>
 /// <param name="destination">The buffer in which to write.</param>
 /// <param name="bytesWritten">
 ///   On success, receives the number of bytes written to <paramref name="destination"/>.
 /// </param>
 /// <returns>
 ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
 ///   length to receive the value, otherwise
 ///   <c>false</c> and the reader does not advance.
 /// </returns>
 /// <remarks>
 ///   This method does not determine if the string used only characters defined by the encoding.
 /// </remarks>
 /// <exception cref="ArgumentOutOfRangeException">
 ///   <paramref name="encodingType"/> is not a known character string type.
 /// </exception>
 /// <exception cref="CryptographicException">
 ///   the next value does not have the correct tag --OR--
 ///   the length encoding is not valid under the current encoding rules --OR--
 ///   the contents are not valid under the current encoding rules
 /// </exception>
 /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
 /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
 /// <seealso cref="TryCopyCharacterString(UniversalTagNumber,Span{char},out int)"/>
 public bool TryCopyCharacterStringBytes(
     UniversalTagNumber encodingType,
     Span <byte> destination,
     out int bytesWritten)
 {
     return(TryCopyCharacterStringBytes(
                new Asn1Tag(encodingType),
                encodingType,
                destination,
                out bytesWritten));
 }
Example #22
0
 /// <summary>
 ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
 ///   encoding type, copying the decoded value into a provided destination buffer.
 /// </summary>
 /// <param name="encodingType">
 ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
 /// </param>
 /// <param name="destination">The buffer in which to write.</param>
 /// <param name="charsWritten">
 ///   On success, receives the number of chars written to <paramref name="destination"/>.
 /// </param>
 /// <returns>
 ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
 ///   length to receive the value, otherwise
 ///   <c>false</c> and the reader does not advance.
 /// </returns>
 /// <exception cref="ArgumentOutOfRangeException">
 ///   <paramref name="encodingType"/> is not a known character string type.
 /// </exception>
 /// <exception cref="CryptographicException">
 ///   the next value does not have the correct tag --OR--
 ///   the length encoding is not valid under the current encoding rules --OR--
 ///   the contents are not valid under the current encoding rules --OR--
 ///   the string did not successfully decode
 /// </exception>
 /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
 /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
 /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,Span{byte},out int)"/>
 public bool TryCopyCharacterString(
     UniversalTagNumber encodingType,
     Span <char> destination,
     out int charsWritten)
 {
     return(this.TryCopyCharacterString(
                new Asn1Tag(encodingType),
                encodingType,
                destination,
                out charsWritten));
 }
Example #23
0
 /// <summary>
 ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
 ///   encoding type, copying the value into a provided destination buffer.
 /// </summary>
 /// <param name="encodingType">
 ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
 /// </param>
 /// <param name="destination">The buffer in which to write.</param>
 /// <param name="bytesWritten">
 ///   On success, receives the number of bytes written to <paramref name="destination"/>.
 /// </param>
 /// <returns>
 ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
 ///   length to receive the value, otherwise
 ///   <c>false</c> and the reader does not advance.
 /// </returns>
 /// <remarks>
 ///   This method does not determine if the string used only characters defined by the encoding.
 /// </remarks>
 /// <exception cref="ArgumentOutOfRangeException">
 ///   <paramref name="encodingType"/> is not a known character string type.
 /// </exception>
 /// <exception cref="CryptographicException">
 ///   the next value does not have the correct tag --OR--
 ///   the length encoding is not valid under the current encoding rules --OR--
 ///   the contents are not valid under the current encoding rules
 /// </exception>
 /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
 /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
 /// <seealso cref="TryCopyCharacterString(UniversalTagNumber,Span{char},out int)"/>
 public bool TryCopyCharacterStringBytes(
     UniversalTagNumber encodingType,
     ArraySegment <byte> destination,
     out int bytesWritten)
 {
     return(this.TryCopyCharacterStringBytes(
                new Asn1Tag(encodingType),
                encodingType,
                destination.AsSpan(),
                out bytesWritten));
 }
Example #24
0
 /// <summary>
 ///   Reads the next value as character string with the specified tag and
 ///   encoding type, copying the value into a provided destination buffer.
 /// </summary>
 /// <param name="expectedTag">The tag to check for before reading.</param>
 /// <param name="encodingType">
 ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
 /// </param>
 /// <param name="destination">The buffer in which to write.</param>
 /// <param name="bytesWritten">
 ///   On success, receives the number of bytes written to <paramref name="destination"/>.
 /// </param>
 /// <returns>
 ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
 ///   length to receive the value, otherwise
 ///   <c>false</c> and the reader does not advance.
 /// </returns>
 /// <remarks>
 ///   This method does not determine if the string used only characters defined by the encoding.
 /// </remarks>
 /// <exception cref="ArgumentOutOfRangeException">
 ///   <paramref name="encodingType"/> is not a known character string type.
 /// </exception>
 /// <exception cref="CryptographicException">
 ///   the next value does not have the correct tag --OR--
 ///   the length encoding is not valid under the current encoding rules --OR--
 ///   the contents are not valid under the current encoding rules
 /// </exception>
 /// <exception cref="ArgumentException">
 ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
 ///   <see cref="TagClass.Universal"/>, but
 ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
 ///   <paramref name="encodingType"/>.
 /// </exception>
 /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
 /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
 /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,Span{char},out int)"/>
 public bool TryCopyCharacterStringBytes(
     Asn1Tag expectedTag,
     UniversalTagNumber encodingType,
     ArraySegment <byte> destination,
     out int bytesWritten)
 {
     return(TryCopyCharacterStringBytes(
                expectedTag,
                encodingType,
                destination.AsSpan(),
                out bytesWritten));
 }
Example #25
0
        private Scope PushTag(Asn1Tag tag, UniversalTagNumber tagType)
        {
            _nestingStack ??= new Stack <StackFrame>();

            Debug.Assert(tag.IsConstructed);
            WriteTag(tag);
            _nestingStack.Push(new StackFrame(tag, _offset, tagType));
            // Indicate that the length is indefinite.
            // We'll come back and clean this up (as appropriate) in PopTag.
            WriteLength(-1);
            return(new Scope(this));
        }
Example #26
0
        /// <summary>
        ///   Reads the next value as character string with the specified tag and
        ///   encoding type, returning the decoded value as a string.
        /// </summary>
        /// <param name="encodingType">
        ///   One of the enumeration values representing the value type to process.
        /// </param>
        /// <param name="expectedTag">
        ///   The tag to check for before reading, or <see langword="null"/> for the universal tag that is
        ///   appropriate to the requested encoding type.
        /// </param>
        /// <returns>
        ///   The decoded value.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="encodingType"/> is not a known character string type.
        /// </exception>
        /// <exception cref="AsnContentException">
        ///   the next value does not have the correct tag.
        ///
        ///   -or-
        ///
        ///   the length encoding is not valid under the current encoding rules.
        ///
        ///   -or-
        ///
        ///   the contents are not valid under the current encoding rules.
        ///
        ///   -or-
        ///
        ///   the string did not successfully decode.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
        ///   <see cref="TagClass.Universal"/>, but
        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
        ///   <paramref name="encodingType"/>.
        /// </exception>
        /// <seealso cref="TryReadPrimitiveCharacterStringBytes"/>
        /// <seealso cref="TryReadCharacterStringBytes"/>
        /// <seealso cref="TryReadCharacterString"/>
        public string ReadCharacterString(UniversalTagNumber encodingType, Asn1Tag?expectedTag = null)
        {
            string ret = AsnDecoder.ReadCharacterString(
                _data.Span,
                RuleSet,
                encodingType,
                out int consumed,
                expectedTag);

            _data = _data.Slice(consumed);
            return(ret);
        }
Example #27
0
 /// <summary>
 ///   Reads the next value as character string with the specified tag and
 ///   encoding type, copying the decoded value into a provided destination buffer.
 /// </summary>
 /// <param name="expectedTag">The tag to check for before reading.</param>
 /// <param name="encodingType">
 ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
 /// </param>
 /// <param name="destination">The buffer in which to write.</param>
 /// <param name="charsWritten">
 ///   On success, receives the number of chars written to <paramref name="destination"/>.
 /// </param>
 /// <returns>
 ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
 ///   length to receive the value, otherwise
 ///   <c>false</c> and the reader does not advance.
 /// </returns>
 /// <exception cref="ArgumentOutOfRangeException">
 ///   <paramref name="encodingType"/> is not a known character string type.
 /// </exception>
 /// <exception cref="CryptographicException">
 ///   the next value does not have the correct tag --OR--
 ///   the length encoding is not valid under the current encoding rules --OR--
 ///   the contents are not valid under the current encoding rules --OR--
 ///   the string did not successfully decode
 /// </exception>
 /// <exception cref="ArgumentException">
 ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
 ///   <see cref="TagClass.Universal"/>, but
 ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
 ///   <paramref name="encodingType"/>.
 /// </exception>
 /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
 /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,ArraySegment{byte},out int)"/>
 /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
 public bool TryCopyCharacterString(
     Asn1Tag expectedTag,
     UniversalTagNumber encodingType,
     ArraySegment <char> destination,
     out int charsWritten)
 {
     return(this.TryCopyCharacterString(
                expectedTag,
                encodingType,
                destination.AsSpan(),
                out charsWritten));
 }
Example #28
0
        // T-REC-X.690-201508 sec 8.23
        private static bool TryReadCharacterStringBytesCore(
            ReadOnlySpan <byte> source,
            AsnEncodingRules ruleSet,
            Asn1Tag expectedTag,
            UniversalTagNumber universalTagNumber,
            Span <byte> destination,
            out int bytesConsumed,
            out int bytesWritten)
        {
            // T-REC-X.690-201508 sec 8.23.3, all character strings are encoded as octet strings.
            if (TryReadPrimitiveOctetStringCore(
                    source,
                    ruleSet,
                    expectedTag,
                    universalTagNumber,
                    out int?contentLength,
                    out int headerLength,
                    out ReadOnlySpan <byte> contents,
                    out int consumed))
            {
                if (contents.Length > destination.Length)
                {
                    bytesWritten  = 0;
                    bytesConsumed = 0;
                    return(false);
                }

                contents.CopyTo(destination);
                bytesWritten  = contents.Length;
                bytesConsumed = consumed;
                return(true);
            }

            bool copied = TryCopyConstructedOctetStringContents(
                Slice(source, headerLength, contentLength),
                ruleSet,
                destination,
                contentLength == null,
                out int bytesRead,
                out bytesWritten);

            if (copied)
            {
                bytesConsumed = headerLength + bytesRead;
            }
            else
            {
                bytesConsumed = 0;
            }

            return(copied);
        }
Example #29
0
        private static bool TryReadUnsignedInteger(
            ReadOnlySpan <byte> source,
            AsnEncodingRules ruleSet,
            int sizeLimit,
            Asn1Tag expectedTag,
            UniversalTagNumber tagNumber,
            out ulong value,
            out int bytesConsumed)
        {
            Debug.Assert(sizeLimit <= sizeof(ulong));

            ReadOnlySpan <byte> contents = GetIntegerContents(
                source,
                ruleSet,
                expectedTag,
                tagNumber,
                out int consumed);

            bool isNegative = (contents[0] & 0x80) != 0;

            if (isNegative)
            {
                bytesConsumed = 0;
                value         = 0;
                return(false);
            }

            // Ignore any padding zeros.
            if (contents.Length > 1 && contents[0] == 0)
            {
                contents = contents.Slice(1);
            }

            if (contents.Length > sizeLimit)
            {
                bytesConsumed = 0;
                value         = 0;
                return(false);
            }

            ulong accum = 0;

            for (int i = 0; i < contents.Length; i++)
            {
                accum <<= 8;
                accum  |= contents[i];
            }

            bytesConsumed = consumed;
            value         = accum;
            return(true);
        }
Example #30
0
        private string ReadCharacterString(
            Asn1Tag expectedTag,
            UniversalTagNumber universalTagNumber,
            Text.Encoding encoding)
        {
            byte[] rented = null;

            // T-REC-X.690-201508 sec 8.23.3, all character strings are encoded as octet strings.
            ReadOnlySpan <byte> contents = GetOctetStringContents(
                expectedTag,
                universalTagNumber,
                out int bytesRead,
                ref rented);

            try
            {
                string str;

                if (contents.Length == 0)
                {
                    str = string.Empty;
                }
                else
                {
                    unsafe
                    {
                        fixed(byte *bytePtr = &MemoryMarshal.GetReference(contents))
                        {
                            try
                            {
                                str = encoding.GetString(bytePtr, contents.Length);
                            }
                            catch (DecoderFallbackException e)
                            {
                                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
                            }
                        }
                    }
                }

                _data = _data.Slice(bytesRead);
                return(str);
            }
            finally
            {
                if (rented != null)
                {
                    Array.Clear(rented, 0, contents.Length);
                    ArrayPool <byte> .Shared.Return(rented);
                }
            }
        }