public static void TagMustBeCorrect_Custom(AsnEncodingRules ruleSet)
        {
            byte[]    inputData = { 0x87, 2, 0, 0x80 };
            byte[]    output    = new byte[inputData.Length];
            AsnReader reader    = new AsnReader(inputData, ruleSet);

            Asn1Tag wrongTag1  = new Asn1Tag(TagClass.Application, 0);
            Asn1Tag wrongTag2  = new Asn1Tag(TagClass.ContextSpecific, 1);
            Asn1Tag correctTag = new Asn1Tag(TagClass.ContextSpecific, 7);

            AssertExtensions.Throws <ArgumentException>(
                "expectedTag",
                () => reader.TryReadPrimitiveOctetString(out _, Asn1Tag.Null));
            AssertExtensions.Throws <ArgumentException>(
                "expectedTag",
                () => reader.TryReadOctetString(output, out _, Asn1Tag.Null));
            AssertExtensions.Throws <ArgumentException>(
                "expectedTag",
                () => reader.ReadOctetString(Asn1Tag.Null));

            Assert.True(reader.HasData, "HasData after bad universal tag");

            Assert.Throws <AsnContentException>(() => reader.TryReadPrimitiveOctetString(out _));
            Assert.Throws <AsnContentException>(() => reader.TryReadOctetString(output, out _));
            Assert.Throws <AsnContentException>(() => reader.ReadOctetString());
            Assert.True(reader.HasData, "HasData after default tag");

            Assert.Throws <AsnContentException>(() => reader.TryReadPrimitiveOctetString(out _, wrongTag1));
            Assert.Throws <AsnContentException>(() => reader.TryReadOctetString(output, out _, wrongTag1));
            Assert.Throws <AsnContentException>(() => reader.ReadOctetString(wrongTag1));
            Assert.True(reader.HasData, "HasData after wrong custom class");

            Assert.Throws <AsnContentException>(() => reader.TryReadPrimitiveOctetString(out _, wrongTag2));
            Assert.Throws <AsnContentException>(() => reader.TryReadOctetString(output, out _, wrongTag2));
            Assert.Throws <AsnContentException>(() => reader.ReadOctetString(wrongTag2));
            Assert.True(reader.HasData, "HasData after wrong custom tag value");

            Assert.True(reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> value, correctTag));
            Assert.Equal("0080", value.ByteArrayToHex());
            Assert.False(reader.HasData, "HasData after reading value");

            reader = new AsnReader(inputData, ruleSet);

            Assert.True(reader.TryReadOctetString(output.AsSpan(1), out int written, correctTag));
            Assert.Equal("0080", output.AsSpan(1, written).ByteArrayToHex());
            Assert.False(reader.HasData, "HasData after reading value");

            reader = new AsnReader(inputData, ruleSet);

            byte[] output2 = reader.ReadOctetString(correctTag);
            Assert.Equal("0080", output2.ByteArrayToHex());
            Assert.False(reader.HasData, "HasData after reading value");
        }
        public static void TryCopyOctetStringBytes_ExtremelyNested()
        {
            byte[] dataBytes = new byte[4 * 16384];

            // This will build 2^14 nested indefinite length values.
            // In the end, none of them contain any content.
            //
            // For what it's worth, the initial algorithm succeeded at 1061, and StackOverflowed with 1062.
            int end = dataBytes.Length / 2;

            // UNIVERSAL OCTET STRING [Constructed]
            const byte Tag = 0x20 | (byte)UniversalTagNumber.OctetString;

            for (int i = 0; i < end; i += 2)
            {
                dataBytes[i] = Tag;
                // Indefinite length
                dataBytes[i + 1] = 0x80;
            }

            AsnReader reader = new AsnReader(dataBytes, AsnEncodingRules.BER);

            int bytesWritten;

            Assert.True(reader.TryReadOctetString(Span <byte> .Empty, out bytesWritten));
            Assert.Equal(0, bytesWritten);

            reader = new AsnReader(dataBytes, AsnEncodingRules.BER);
            byte[] output2 = reader.ReadOctetString();

            // It's Same (ReferenceEqual) on .NET Core, but just Equal on .NET Framework
            Assert.Equal(Array.Empty <byte>(), output2);
        }
Esempio n. 3
0
        internal static ReadOnlyMemory <byte> GetContent(
            ReadOnlyMemory <byte> wrappedContent,
            string contentType)
        {
            // Read the input.
            //
            // PKCS7's id-data is written in both PKCS#7 and CMS as an OCTET STRING wrapping
            // the arbitrary bytes, so the OCTET STRING must always be present.
            //
            // For other types, CMS says to always write an OCTET STRING, and to put the properly
            // encoded data within it.
            // PKCS#7 originally ommitted the OCTET STRING wrapper for this model, so this is the
            // dynamic adapter.
            //
            // See https://tools.ietf.org/html/rfc5652#section-5.2.1
            byte[]? rented = null;
            int bytesWritten = 0;

            try
            {
                AsnReader reader = new AsnReader(wrappedContent, AsnEncodingRules.BER);

                if (reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> inner))
                {
                    return(inner);
                }

                rented = CryptoPool.Rent(wrappedContent.Length);

                if (!reader.TryReadOctetString(rented, out bytesWritten))
                {
                    Debug.Fail($"TryCopyOctetStringBytes failed with an array larger than the encoded value");
                    throw new CryptographicException();
                }

                return(rented.AsSpan(0, bytesWritten).ToArray());
            }
            catch (Exception) when(contentType != Oids.Pkcs7Data)
            {
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }
            finally
            {
                if (rented != null)
                {
                    CryptoPool.Return(rented, bytesWritten);
                }
            }

            // PKCS#7 encoding for something other than id-data.
            Debug.Assert(contentType != Oids.Pkcs7Data);
            return(wrappedContent);
        }
        public static void TryReadOctetStringBytes_Fails(AsnEncodingRules ruleSet, string inputHex)
        {
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, ruleSet);

            bool didRead = reader.TryReadOctetString(
                Span <byte> .Empty,
                out int bytesWritten);

            Assert.False(didRead, "reader.TryReadOctetString");
            Assert.Equal(0, bytesWritten);
        }
        private static void TryReadOctetStringBytes_Throws_Helper(
            AsnEncodingRules ruleSet,
            byte[] input)
        {
            AsnReader reader = new AsnReader(input, ruleSet);

            Assert.Throws <AsnContentException>(
                () =>
            {
                reader.TryReadOctetString(
                    Span <byte> .Empty,
                    out int bytesWritten);
            });
        }
        public static void TryReadOctetStringBytes_Success(
            AsnEncodingRules ruleSet,
            string inputHex,
            string expectedHex)
        {
            byte[]    inputData = inputHex.HexToByteArray();
            byte[]    output    = new byte[expectedHex.Length / 2];
            AsnReader reader    = new AsnReader(inputData, ruleSet);

            bool didRead = reader.TryReadOctetString(
                output,
                out int bytesWritten);

            Assert.True(didRead, "reader.TryReadOctetString");
            Assert.Equal(expectedHex, output.AsSpan(0, bytesWritten).ByteArrayToHex());

            reader = new AsnReader(inputData, ruleSet);
            byte[] output2 = reader.ReadOctetString();
            Assert.Equal(output, output2);
        }
        public static void TryCopyOctetStringBytes_Success_CER_MaxPrimitiveLength()
        {
            // CER says that the maximum encoding length for an OctetString primitive
            // is 1000.
            //
            // So we need 04 [1000] { 1000 anythings }
            // 1000 => 0x3E8, so the length encoding is 82 03 E8.
            // 1000 + 3 + 1 == 1004
            byte[] input = new byte[1004];
            input[0] = 0x04;
            input[1] = 0x82;
            input[2] = 0x03;
            input[3] = 0xE8;

            // Content
            input[4]    = 0x02;
            input[5]    = 0xA0;
            input[1002] = 0xA5;
            input[1003] = 0xFC;

            byte[] output = new byte[1000];

            AsnReader reader = new AsnReader(input, AsnEncodingRules.CER);

            bool success = reader.TryReadOctetString(
                output,
                out int bytesWritten);

            Assert.True(success, "reader.TryReadOctetString");
            Assert.Equal(1000, bytesWritten);

            Assert.Equal(
                input.AsSpan(4).ByteArrayToHex(),
                output.ByteArrayToHex());

            reader = new AsnReader(input, AsnEncodingRules.CER);
            byte[] output2 = reader.ReadOctetString();
            Assert.Equal(output, output2);
        }
        public static void TryReadPrimitiveOctetStringBytes_Throws_CER_TooLong()
        {
            // CER says that the maximum encoding length for an OctetString primitive
            // is 1000.
            //
            // So we need 04 [1001] { 1001 0x00s }
            // 1001 => 0x3E9, so the length encoding is 82 03 E9.
            // 1001 + 3 + 1 == 1005
            byte[] input = new byte[1005];
            input[0] = 0x04;
            input[1] = 0x82;
            input[2] = 0x03;
            input[3] = 0xE9;

            AsnReader reader = new AsnReader(input, AsnEncodingRules.CER);

            Assert.Throws <AsnContentException>(
                () => reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents));

            Assert.Throws <AsnContentException>(
                () => reader.TryReadOctetString(new byte[input.Length], out _));

            Assert.Throws <AsnContentException>(() => reader.ReadOctetString());
        }
Esempio n. 9
0
        internal static AlgorithmIdentifier ToPresentationObject(this AlgorithmIdentifierAsn asn)
        {
            int keyLength;

            byte[] parameters = Array.Empty <byte>();

            switch (asn.Algorithm)
            {
            case Oids.Rc2Cbc:
            {
                if (asn.Parameters == null)
                {
                    keyLength = 0;
                    break;
                }

                Rc2CbcParameters rc2Params = Rc2CbcParameters.Decode(
                    asn.Parameters.Value,
                    AsnEncodingRules.BER);

                int keySize = rc2Params.GetEffectiveKeyBits();

                // These are the only values .NET Framework would set.
                switch (keySize)
                {
                case 40:
                case 56:
                case 64:
                case 128:
                    keyLength = keySize;
                    break;

                default:
                    keyLength = 0;
                    break;
                }

                break;
            }

            case Oids.Rc4:
            {
                if (asn.Parameters == null)
                {
                    keyLength = 0;
                    break;
                }

                int saltLen = 0;

                try
                {
                    AsnReader reader = new AsnReader(asn.Parameters.Value, AsnEncodingRules.BER);

                    // DER NULL is considered the same as not present.
                    // No call to ReadNull() is necessary because the serializer already verified that
                    // there's no data after the [AnyValue] value.
                    if (reader.PeekTag() != Asn1Tag.Null)
                    {
                        if (reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents))
                        {
                            saltLen = contents.Length;
                        }
                        else
                        {
                            Span <byte> salt = stackalloc byte[KeyLengths.Rc4Max_128Bit / 8];

                            if (!reader.TryReadOctetString(salt, out saltLen))
                            {
                                throw new CryptographicException();
                            }
                        }
                    }
                }
                catch (AsnContentException e)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
                }

                keyLength = KeyLengths.Rc4Max_128Bit - 8 * saltLen;
                break;
            }

            case Oids.DesCbc:
                keyLength = KeyLengths.Des_64Bit;
                break;

            case Oids.TripleDesCbc:
                keyLength = KeyLengths.TripleDes_192Bit;
                break;

            case Oids.RsaOaep when !asn.HasNullEquivalentParameters():
                keyLength = 0;
                Debug.Assert(asn.Parameters != null);
                parameters = asn.Parameters.Value.ToArray();
                break;

            default:
                // .NET Framework doesn't set a keylength for AES, or any other algorithm than the ones
                // listed here.
                keyLength = 0;
                break;
            }

            return(new AlgorithmIdentifier(new Oid(asn.Algorithm), keyLength)
            {
                Parameters = parameters
            });
        }
        public static void TryCopyOctetStringBytes_Success_CER_MinConstructedLength()
        {
            // CER says that the maximum encoding length for an OctetString primitive
            // is 1000, and that a constructed form must be used for values greater
            // than 1000 bytes, with segments dividing up for each thousand
            // [1000, 1000, ..., len%1000].
            //
            // So our smallest constructed form is 1001 bytes, [1000, 1]
            //
            // 24 80 (indefinite constructed octet string)
            //    04 82 03 E9 (primitive octet string, 1000 bytes)
            //       [1000 content bytes]
            //    04 01 (primitive octet string, 1 byte)
            //       pp
            //    00 00 (end of contents, 0 bytes)
            // 1011 total.
            byte[] input  = new byte[1011];
            int    offset = 0;

            // CONSTRUCTED OCTET STRING (Indefinite)
            input[offset++] = 0x24;
            input[offset++] = 0x80;
            // OCTET STRING (1000)
            input[offset++] = 0x04;
            input[offset++] = 0x82;
            input[offset++] = 0x03;
            input[offset++] = 0xE8;

            // Primitive 1: (55 A0 :: A5 FC) (1000)
            input[offset++] = 0x55;
            input[offset]   = 0xA0;
            offset         += 997;
            input[offset++] = 0xA5;
            input[offset++] = 0xFC;

            // OCTET STRING (1)
            input[offset++] = 0x04;
            input[offset++] = 0x01;

            // Primitive 2: One more byte
            input[offset] = 0xF7;

            byte[] expected = new byte[1001];
            offset             = 0;
            expected[offset++] = 0x55;
            expected[offset]   = 0xA0;
            offset            += 997;
            expected[offset++] = 0xA5;
            expected[offset++] = 0xFC;
            expected[offset]   = 0xF7;

            byte[] output = new byte[1001];

            AsnReader reader = new AsnReader(input, AsnEncodingRules.CER);

            bool success = reader.TryReadOctetString(
                output,
                out int bytesWritten);

            Assert.True(success, "reader.TryReadOctetString");
            Assert.Equal(1001, bytesWritten);

            Assert.Equal(
                expected.ByteArrayToHex(),
                output.ByteArrayToHex());

            reader = new AsnReader(input, AsnEncodingRules.CER);
            byte[] output2 = reader.ReadOctetString();
            Assert.Equal(output, output2);
        }