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 ExpectedTag_IgnoresConstructed(
            AsnEncodingRules ruleSet,
            string inputHex,
            TagClass tagClass,
            int tagValue)
        {
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, ruleSet);

            Assert.True(
                reader.TryReadPrimitiveOctetString(
                    out ReadOnlyMemory <byte> val1,
                    new Asn1Tag(tagClass, tagValue, true)));

            Assert.False(reader.HasData);

            reader = new AsnReader(inputData, ruleSet);

            Assert.True(
                reader.TryReadPrimitiveOctetString(
                    out ReadOnlyMemory <byte> val2,
                    new Asn1Tag(tagClass, tagValue, false)));

            Assert.False(reader.HasData);

            Assert.Equal(val1.ByteArrayToHex(), val2.ByteArrayToHex());
        }
        public static void TryReadPrimitiveOctetStringBytes_Success_CER_MaxLength()
        {
            // 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;

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

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

            bool success = reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents);

            Assert.True(success, "reader.TryReadOctetStringBytes");
            Assert.Equal(1000, contents.Length);

            // Check that it is, in fact, the same memory. No copies with this API.
            Assert.True(
                Unsafe.AreSame(
                    ref MemoryMarshal.GetReference(contents.Span),
                    ref input[4]));
        }
Esempio n. 4
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 TagMustBeCorrect_Universal(AsnEncodingRules ruleSet)
        {
            byte[]    inputData = { 4, 1, 0x7E };
            AsnReader reader    = new AsnReader(inputData, ruleSet);

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

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

            Assert.Throws <AsnContentException>(
                () => reader.TryReadPrimitiveOctetString(out _, new Asn1Tag(TagClass.ContextSpecific, 0)));

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

            Assert.True(reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> value));
            Assert.Equal("7E", value.ByteArrayToHex());
            Assert.False(reader.HasData, "HasData after read");
        }
        public static void TryReadPrimitiveOctetStringBytes_Throws(
            string description,
            AsnEncodingRules ruleSet,
            string inputHex)
        {
            _ = description;
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, ruleSet);

            Assert.Throws <AsnContentException>(
                () => reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents));
        }
        public static void TryReadPrimitiveOctetStringBytes_Success(
            AsnEncodingRules ruleSet,
            int expectedLength,
            string inputHex)
        {
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, ruleSet);

            bool didRead = reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents);

            Assert.True(didRead, "reader.TryReadOctetStringBytes");
            Assert.Equal(expectedLength, contents.Length);
        }
Esempio n. 8
0
        private static void AssertExtension(AsnReader extensions, string oid, bool critical, int index, byte[] bytes)
        {
            AsnReader extension = extensions.ReadSequence();

            Assert.Equal(oid, extension.ReadObjectIdentifier());

            if (critical)
            {
                Assert.True(extension.ReadBoolean(), $"{oid} is critical");
            }

            Assert.True(extension.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> extensionBytes));
            AssertRefSame(extensionBytes, ref bytes[index], $"{oid} extension value is at byte {index}");
        }
        public static void TryReadPrimitiveOctetStringBytes_Fails(
            string description,
            AsnEncodingRules ruleSet,
            string inputHex)
        {
            _ = description;
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, ruleSet);

            bool didRead = reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents);

            Assert.False(didRead, "reader.TryReadOctetStringBytes");
            Assert.Equal(0, contents.Length);
        }
        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. 11
0
        public static void ReadMicrosoftComCert()
        {
            byte[]    bytes      = MicrosoftDotComSslCertBytes;
            AsnReader fileReader = new AsnReader(bytes, AsnEncodingRules.DER);

            AsnReader certReader = fileReader.ReadSequence();

            Assert.False(fileReader.HasData, "fileReader.HasData");

            AsnReader tbsCertReader = certReader.ReadSequence();
            AsnReader sigAlgReader  = certReader.ReadSequence();

            Assert.True(
                certReader.TryReadPrimitiveBitString(
                    out int unusedBitCount,
                    out ReadOnlyMemory <byte> signature),
                "certReader.TryReadPrimitiveBitStringValue");

            Assert.Equal(0, unusedBitCount);
            AssertRefSame(signature, ref bytes[1176], "Signature is a ref to bytes[1176]");

            Assert.False(certReader.HasData, "certReader.HasData");

            AsnReader versionExplicitWrapper = tbsCertReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

            Assert.True(versionExplicitWrapper.TryReadInt32(out int certVersion));
            Assert.Equal(2, certVersion);
            Assert.False(versionExplicitWrapper.HasData, "versionExplicitWrapper.HasData");

            ReadOnlyMemory <byte> serialBytes = tbsCertReader.ReadIntegerBytes();

            AssertRefSame(serialBytes, ref bytes[15], "Serial number starts at bytes[15]");

            AsnReader tbsSigAlgReader = tbsCertReader.ReadSequence();

            Assert.Equal("1.2.840.113549.1.1.11", tbsSigAlgReader.ReadObjectIdentifier());
            Assert.True(tbsSigAlgReader.HasData, "tbsSigAlgReader.HasData before ReadNull");
            tbsSigAlgReader.ReadNull();
            Assert.False(tbsSigAlgReader.HasData, "tbsSigAlgReader.HasData after ReadNull");

            AsnReader issuerReader    = tbsCertReader.ReadSequence();
            Asn1Tag   printableString = new Asn1Tag(UniversalTagNumber.PrintableString);

            AssertRdn(issuerReader, "2.5.4.6", 57, printableString, bytes, "issuer[C]");
            AssertRdn(issuerReader, "2.5.4.10", 70, printableString, bytes, "issuer[O]");
            AssertRdn(issuerReader, "2.5.4.11", 101, printableString, bytes, "issuer[OU]");
            AssertRdn(issuerReader, "2.5.4.3", 134, printableString, bytes, "issuer[CN]");
            Assert.False(issuerReader.HasData, "issuerReader.HasData");

            AsnReader validityReader = tbsCertReader.ReadSequence();

            Assert.Equal(new DateTimeOffset(2014, 10, 15, 0, 0, 0, TimeSpan.Zero), validityReader.ReadUtcTime());
            Assert.Equal(new DateTimeOffset(2016, 10, 15, 23, 59, 59, TimeSpan.Zero), validityReader.ReadUtcTime());
            Assert.False(validityReader.HasData, "validityReader.HasData");

            AsnReader subjectReader = tbsCertReader.ReadSequence();
            Asn1Tag   utf8String    = new Asn1Tag(UniversalTagNumber.UTF8String);

            AssertRdn(subjectReader, "1.3.6.1.4.1.311.60.2.1.3", 220, printableString, bytes, "subject[EV Country]");
            AssertRdn(subjectReader, "1.3.6.1.4.1.311.60.2.1.2", 241, utf8String, bytes, "subject[EV State]", "Washington");
            AssertRdn(subjectReader, "2.5.4.15", 262, printableString, bytes, "subject[Business Category]");
            AssertRdn(subjectReader, "2.5.4.5", 293, printableString, bytes, "subject[Serial Number]");
            AssertRdn(subjectReader, "2.5.4.6", 313, printableString, bytes, "subject[C]");
            AssertRdn(subjectReader, "2.5.4.17", 326, utf8String, bytes, "subject[Postal Code]", "98052");
            AssertRdn(subjectReader, "2.5.4.8", 342, utf8String, bytes, "subject[ST]", "Washington");
            AssertRdn(subjectReader, "2.5.4.7", 363, utf8String, bytes, "subject[L]", "Redmond");
            AssertRdn(subjectReader, "2.5.4.9", 381, utf8String, bytes, "subject[Street Address]", "1 Microsoft Way");
            AssertRdn(subjectReader, "2.5.4.10", 407, utf8String, bytes, "subject[O]", "Microsoft Corporation");
            AssertRdn(subjectReader, "2.5.4.11", 439, utf8String, bytes, "subject[OU]", "MSCOM");
            AssertRdn(subjectReader, "2.5.4.3", 455, utf8String, bytes, "subject[CN]", "www.microsoft.com");
            Assert.False(subjectReader.HasData, "subjectReader.HasData");

            AsnReader subjectPublicKeyInfo = tbsCertReader.ReadSequence();
            AsnReader spkiAlgorithm        = subjectPublicKeyInfo.ReadSequence();

            Assert.Equal("1.2.840.113549.1.1.1", spkiAlgorithm.ReadObjectIdentifier());
            spkiAlgorithm.ReadNull();
            Assert.False(spkiAlgorithm.HasData, "spkiAlgorithm.HasData");

            Assert.True(
                subjectPublicKeyInfo.TryReadPrimitiveBitString(
                    out unusedBitCount,
                    out ReadOnlyMemory <byte> encodedPublicKey),
                "subjectPublicKeyInfo.TryReadBitStringBytes");

            Assert.Equal(0, unusedBitCount);
            AssertRefSame(encodedPublicKey, ref bytes[498], "Encoded public key starts at byte 498");

            Assert.False(subjectPublicKeyInfo.HasData, "subjectPublicKeyInfo.HasData");

            AsnReader publicKeyReader    = new AsnReader(encodedPublicKey, AsnEncodingRules.DER);
            AsnReader rsaPublicKeyReader = publicKeyReader.ReadSequence();

            AssertRefSame(rsaPublicKeyReader.ReadIntegerBytes(), ref bytes[506], "RSA Modulus is at bytes[502]");
            Assert.True(rsaPublicKeyReader.TryReadInt32(out int rsaExponent));
            Assert.Equal(65537, rsaExponent);
            Assert.False(rsaPublicKeyReader.HasData, "rsaPublicKeyReader.HasData");
            Assert.False(publicKeyReader.HasData, "publicKeyReader.HasData");

            AsnReader extensionsContainer = tbsCertReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
            AsnReader extensions          = extensionsContainer.ReadSequence();

            Assert.False(extensionsContainer.HasData, "extensionsContainer.HasData");

            AsnReader sanExtension = extensions.ReadSequence();

            Assert.Equal("2.5.29.17", sanExtension.ReadObjectIdentifier());
            Assert.True(sanExtension.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> sanExtensionBytes));
            Assert.False(sanExtension.HasData, "sanExtension.HasData");

            AsnReader sanExtensionPayload = new AsnReader(sanExtensionBytes, AsnEncodingRules.DER);
            AsnReader sanExtensionValue   = sanExtensionPayload.ReadSequence();

            Assert.False(sanExtensionPayload.HasData, "sanExtensionPayload.HasData");
            Asn1Tag dnsName = new Asn1Tag(TagClass.ContextSpecific, 2);

            Assert.Equal("www.microsoft.com", sanExtensionValue.ReadCharacterString(UniversalTagNumber.IA5String, dnsName));
            Assert.Equal("wwwqa.microsoft.com", sanExtensionValue.ReadCharacterString(UniversalTagNumber.IA5String, dnsName));
            Assert.False(sanExtensionValue.HasData, "sanExtensionValue.HasData");

            AsnReader basicConstraints = extensions.ReadSequence();

            Assert.Equal("2.5.29.19", basicConstraints.ReadObjectIdentifier());
            Assert.True(basicConstraints.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> basicConstraintsBytes));

            AsnReader basicConstraintsPayload = new AsnReader(basicConstraintsBytes, AsnEncodingRules.DER);
            AsnReader basicConstraintsValue   = basicConstraintsPayload.ReadSequence();

            Assert.False(basicConstraintsValue.HasData, "basicConstraintsValue.HasData");
            Assert.False(basicConstraintsPayload.HasData, "basicConstraintsPayload.HasData");

            AsnReader keyUsageExtension = extensions.ReadSequence();

            Assert.Equal("2.5.29.15", keyUsageExtension.ReadObjectIdentifier());
            Assert.True(keyUsageExtension.ReadBoolean(), "keyUsageExtension.ReadBoolean() (IsCritical)");
            Assert.True(keyUsageExtension.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> keyUsageBytes));

            AsnReader keyUsagePayload = new AsnReader(keyUsageBytes, AsnEncodingRules.DER);

            Assert.Equal(
                X509KeyUsageCSharpStyle.DigitalSignature | X509KeyUsageCSharpStyle.KeyEncipherment,
                keyUsagePayload.ReadNamedBitListValue <X509KeyUsageCSharpStyle>());

            Assert.False(keyUsagePayload.HasData, "keyUsagePayload.HasData");

            AssertExtension(extensions, "2.5.29.37", false, 863, bytes);
            AssertExtension(extensions, "2.5.29.32", false, 894, bytes);
            AssertExtension(extensions, "2.5.29.35", false, 998, bytes);
            AssertExtension(extensions, "2.5.29.31", false, 1031, bytes);
            AssertExtension(extensions, "1.3.6.1.5.5.7.1.1", false, 1081, bytes);
            Assert.False(extensions.HasData, "extensions.HasData");

            Assert.Equal("1.2.840.113549.1.1.11", sigAlgReader.ReadObjectIdentifier());
            sigAlgReader.ReadNull();
            Assert.False(sigAlgReader.HasData);
        }
Esempio n. 12
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
            });
        }