Exemple #1
0
        public static void TagMustBeCorrect_Custom(PublicEncodingRules ruleSet)
        {
            byte[]    inputData = { 0x87, 2, 0, 0x80 };
            AsnReader reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);

            AssertExtensions.Throws <ArgumentException>(
                "expectedTag",
                () => reader.ReadEnumeratedValue <ShortBacked>(Asn1Tag.Null));

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

            Assert.Throws <CryptographicException>(() => reader.ReadEnumeratedValue <ShortBacked>());

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

            Assert.Throws <CryptographicException>(
                () => reader.ReadEnumeratedValue <ShortBacked>(new Asn1Tag(TagClass.Application, 0)));

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

            Assert.Throws <CryptographicException>(
                () => reader.ReadEnumeratedValue <ShortBacked>(new Asn1Tag(TagClass.ContextSpecific, 1)));

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

            ShortBacked value = reader.ReadEnumeratedValue <ShortBacked>(new Asn1Tag(TagClass.ContextSpecific, 7));

            Assert.Equal((ShortBacked)0x80, value);
            Assert.False(reader.HasData, "HasData after reading value");
        }
Exemple #2
0
        public static void ReadEnumeratedValue_NonEnumType(PublicEncodingRules ruleSet)
        {
            byte[]    data   = { 0x0A, 0x01, 0x00 };
            AsnReader reader = new AsnReader(data, (AsnEncodingRules)ruleSet);

            Assert.Throws <ArgumentException>(() => reader.ReadEnumeratedValue <Guid>());
        }
Exemple #3
0
        public static void ReadEnumeratedValue_Invalid_ULong(PublicEncodingRules ruleSet, string inputHex)
        {
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);

            Assert.Throws <CryptographicException>(() => reader.ReadEnumeratedValue <ULongBacked>());
        }
Exemple #4
0
        public static void ReadEnumeratedValue_Invalid_Long(AsnEncodingRules ruleSet, string inputHex)
        {
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, ruleSet);

            Assert.Throws <AsnContentException>(() => reader.ReadEnumeratedValue <LongBacked>());
        }
Exemple #5
0
        public static void ReadEnumeratedValue_FlagsEnum(PublicEncodingRules ruleSet)
        {
            byte[]    data   = { 0x0A, 0x01, 0x00 };
            AsnReader reader = new AsnReader(data, (AsnEncodingRules)ruleSet);

            AssertExtensions.Throws <ArgumentException>(
                "tEnum",
                () => reader.ReadEnumeratedValue <AssemblyFlags>());
        }
Exemple #6
0
        public static void TagMustBeCorrect_Universal(PublicEncodingRules ruleSet)
        {
            byte[]    inputData = { 0x0A, 1, 0x7E };
            AsnReader reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);

            AssertExtensions.Throws <ArgumentException>(
                "expectedTag",
                () => reader.ReadEnumeratedValue <ShortBacked>(Asn1Tag.Null));

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

            Assert.Throws <CryptographicException>(
                () => reader.ReadEnumeratedValue <ShortBacked>(new Asn1Tag(TagClass.ContextSpecific, 0)));

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

            ShortBacked value = reader.ReadEnumeratedValue <ShortBacked>();

            Assert.Equal((ShortBacked)0x7E, value);
            Assert.False(reader.HasData, "HasData after read");
        }
Exemple #7
0
        private static void GetExpectedValue <TEnum>(
            PublicEncodingRules ruleSet,
            TEnum expectedValue,
            string inputHex)
            where TEnum : struct
        {
            byte[]    inputData = inputHex.HexToByteArray();
            AsnReader reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);
            TEnum     value     = reader.ReadEnumeratedValue <TEnum>();

            Assert.Equal(expectedValue, value);
        }
Exemple #8
0
        public SearchRequest TryDecode(AsnReader reader, byte[] input)
        {
            SearchRequest searchRequest = new SearchRequest
            {
                RawPacket = input,
            };

            Asn1Tag   bindRequestApplication = new Asn1Tag(TagClass.Application, 3);
            AsnReader subReader = reader.ReadSequence(bindRequestApplication);

            searchRequest.BaseObject = System.Text.Encoding.ASCII.GetString(subReader.ReadOctetString());
            SearchRequest.ScopeEnum        scope = subReader.ReadEnumeratedValue <SearchRequest.ScopeEnum>();
            SearchRequest.DerefAliasesEnum deref = subReader.ReadEnumeratedValue <SearchRequest.DerefAliasesEnum>();
            BigInteger sizeLimit = subReader.ReadInteger();
            BigInteger timeLimit = subReader.ReadInteger();
            bool       typesOnly = subReader.ReadBoolean();

            searchRequest.Filter = DecodeSearchFilter(subReader);

            return(searchRequest);
        }
Exemple #9
0
        public static void ExpectedTag_IgnoresConstructed(
            AsnEncodingRules ruleSet,
            string inputHex,
            TagClass tagClass,
            int tagValue)
        {
            Asn1Tag primitiveTag   = new Asn1Tag(tagClass, tagValue, false);
            Asn1Tag constructedTag = new Asn1Tag(tagClass, tagValue, true);

            byte[] inputData = inputHex.HexToByteArray();

            AsnReader   reader = new AsnReader(inputData, ruleSet);
            ShortBacked val1   = reader.ReadEnumeratedValue <ShortBacked>(constructedTag);

            Assert.False(reader.HasData);

            reader = new AsnReader(inputData, ruleSet);
            ShortBacked val2 = reader.ReadEnumeratedValue <ShortBacked>(primitiveTag);

            Assert.False(reader.HasData);

            Assert.Equal(val1, val2);

            reader = new AsnReader(inputData, ruleSet);
            ShortBacked val3 = (ShortBacked)reader.ReadEnumeratedValue(typeof(ShortBacked), constructedTag);

            Assert.False(reader.HasData);

            Assert.Equal(val1, val3);

            reader = new AsnReader(inputData, ruleSet);
            ShortBacked val4 = (ShortBacked)reader.ReadEnumeratedValue(typeof(ShortBacked), primitiveTag);

            Assert.False(reader.HasData);

            Assert.Equal(val1, val4);

            reader = new AsnReader(inputData, ruleSet);
            ReadOnlyMemory <byte> bytes1 = reader.ReadEnumeratedBytes(constructedTag);

            Assert.False(reader.HasData);

            reader = new AsnReader(inputData, ruleSet);
            ReadOnlyMemory <byte> bytes2 = reader.ReadEnumeratedBytes(primitiveTag);

            Assert.False(reader.HasData);

            Assert.Equal(bytes1.ByteArrayToHex(), bytes2.ByteArrayToHex());
            Assert.Equal("FF", bytes1.ByteArrayToHex());
        }
Exemple #10
0
        public static void ExpectedTag_IgnoresConstructed(
            PublicEncodingRules ruleSet,
            string inputHex,
            PublicTagClass tagClass,
            int tagValue)
        {
            byte[]      inputData = inputHex.HexToByteArray();
            AsnReader   reader    = new AsnReader(inputData, (AsnEncodingRules)ruleSet);
            ShortBacked val1      = reader.ReadEnumeratedValue <ShortBacked>(new Asn1Tag((TagClass)tagClass, tagValue, true));

            Assert.False(reader.HasData);
            reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet);
            ShortBacked val2 = reader.ReadEnumeratedValue <ShortBacked>(new Asn1Tag((TagClass)tagClass, tagValue, false));

            Assert.False(reader.HasData);

            Assert.Equal(val1, val2);
        }
Exemple #11
0
        public byte[]? GetOutgoingBlob(byte[]?incomingBlob)
        {
            if (_spnegoMechList == null && incomingBlob.AsSpan().StartsWith(NtlmHeader))
            {
                _ntlmPassthrough = true;
                // Windows often sends pure NTLM instead of proper Negotiate, handle that as passthrough
                byte[]? outgoingBlob = _ntlmServer.GetOutgoingBlob(incomingBlob);
                IsAuthenticated      = _ntlmServer.IsAuthenticated;
                return(outgoingBlob);
            }

            Assert.False(_ntlmPassthrough);

            AsnReader reader = new AsnReader(incomingBlob, AsnEncodingRules.DER);

            if (_spnegoMechList == null)
            {
                AsnReader initialContextTokenReader = reader.ReadSequence(new Asn1Tag(TagClass.Application, 0));

                string spNegoOid = initialContextTokenReader.ReadObjectIdentifier();
                Assert.Equal(SpnegoOid, spNegoOid);

                AsnReader negTokenInitReader   = initialContextTokenReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenInit)).ReadSequence();
                AsnReader mechTypesOuterReader = negTokenInitReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechTypes));
                _spnegoMechList = mechTypesOuterReader.PeekEncodedValue().ToArray();

                bool      hasNtlm         = false;
                bool      isNtlmPreferred = false;
                bool      first           = true;
                AsnReader mechTypesReader = mechTypesOuterReader.ReadSequence();
                while (mechTypesReader.HasData)
                {
                    string mechType = mechTypesReader.ReadObjectIdentifier();
                    if (mechType == NtlmOid)
                    {
                        hasNtlm         = true;
                        isNtlmPreferred = first;
                    }
                    first = false;
                }

                // Skip context flags, if present
                if (negTokenInitReader.HasData && negTokenInitReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.ReqFlags)))
                {
                    negTokenInitReader.ReadSequence();
                }

                byte[]? mechToken = null;
                if (negTokenInitReader.HasData && negTokenInitReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechToken)))
                {
                    AsnReader mechTokenReader = negTokenInitReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechToken));
                    mechToken = mechTokenReader.ReadOctetString();
                    Assert.False(mechTokenReader.HasData);
                }

                byte[]? mechListMIC = null;
                if (negTokenInitReader.HasData && negTokenInitReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechListMIC)))
                {
                    AsnReader mechListMICReader = negTokenInitReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechListMIC));
                    mechListMIC = mechListMICReader.ReadOctetString();
                    Assert.False(mechListMICReader.HasData);
                }

                Assert.True(hasNtlm);

                // If the preferred mechanism was NTLM then proceed with the given token
                byte[]? outgoingBlob = null;
                if (isNtlmPreferred && mechToken != null)
                {
                    Assert.Null(mechListMIC);
                    outgoingBlob = _ntlmServer.GetOutgoingBlob(mechToken);
                }

                // Generate reply
                AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
                using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp)))
                {
                    using (writer.PushSequence())
                    {
                        using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState)))
                        {
                            if (RequestMIC)
                            {
                                writer.WriteEnumeratedValue(NegState.RequestMic);
                            }
                            else
                            {
                                writer.WriteEnumeratedValue(NegState.AcceptIncomplete);
                            }
                        }

                        using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.SupportedMech)))
                        {
                            writer.WriteObjectIdentifier(NtlmOid);
                        }

                        if (outgoingBlob != null)
                        {
                            using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken)))
                            {
                                writer.WriteOctetString(outgoingBlob);
                            }
                        }
                    }
                }

                return(writer.Encode());
            }
            else
            {
                AsnReader negTokenRespReader = reader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp)).ReadSequence();

                Assert.True(negTokenRespReader.HasData);
                NegState?clientState;
                if (negTokenRespReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState)))
                {
                    AsnReader valueReader = negTokenRespReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState));
                    clientState = valueReader.ReadEnumeratedValue <NegState>();
                    Assert.False(valueReader.HasData);

                    Assert.NotEqual(NegState.Reject, clientState);
                    Assert.NotEqual(NegState.RequestMic, clientState);
                }

                // Client should not send mechanism
                Assert.False(negTokenRespReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.SupportedMech)));

                byte[]? mechToken = null;
                if (negTokenRespReader.HasData && negTokenRespReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken)))
                {
                    AsnReader mechTokenReader = negTokenRespReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken));
                    mechToken = mechTokenReader.ReadOctetString();
                    Assert.False(mechTokenReader.HasData);
                }

                byte[]? mechListMIC = null;
                if (negTokenRespReader.HasData && negTokenRespReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.MechListMIC)))
                {
                    AsnReader mechListMICReader = negTokenRespReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.MechListMIC));
                    mechListMIC = mechListMICReader.ReadOctetString();
                    Assert.False(mechListMICReader.HasData);
                }

                Assert.NotNull(mechToken);
                byte[]? outgoingBlob = _ntlmServer.GetOutgoingBlob(mechToken);

                if (_ntlmServer.IsAuthenticated)
                {
                    if (RequestMIC)
                    {
                        Assert.NotNull(mechListMIC);
                    }

                    // Validate mechListMIC, if present
                    if (mechListMIC is not null)
                    {
                        _ntlmServer.VerifyMIC(_spnegoMechList, mechListMIC);
                    }
                }
                else
                {
                    Assert.Null(mechListMIC);
                }

                // Generate reply
                AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
                using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp)))
                {
                    using (writer.PushSequence())
                    {
                        using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState)))
                        {
                            if (_ntlmServer.IsAuthenticated)
                            {
                                writer.WriteEnumeratedValue(NegState.AcceptCompleted);
                            }
                            else if (outgoingBlob != null)
                            {
                                writer.WriteEnumeratedValue(NegState.AcceptIncomplete);
                            }
                            else
                            {
                                writer.WriteEnumeratedValue(NegState.Reject);
                            }
                        }

                        if (outgoingBlob != null)
                        {
                            using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken)))
                            {
                                writer.WriteOctetString(outgoingBlob);
                            }
                        }

                        if (mechListMIC != null)
                        {
                            using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.MechListMIC)))
                            {
                                Span <byte> mic = stackalloc byte[16];
                                _ntlmServer.GetMIC(_spnegoMechList, mic);
                                writer.WriteOctetString(mic);

                                // MS-SPNG section 3.2.5.1 NTLM RC4 Key State for MechListMIC and First Signed Message
                                // specifies that the RC4 sealing keys are reset back to the initial state for the
                                // first message.
                                _ntlmServer.ResetKeys();
                            }
                        }
                    }
                }

                IsAuthenticated = _ntlmServer.IsAuthenticated;

                return(writer.Encode());
            }
        }
Exemple #12
0
        public unsafe string ProcessNegotiateChallenge(string challengeString)
        {
            Console.WriteLine($"ChallengesString {challengeString}");

            NegState state = NegState.Unknown;
            string   mech  = null;

            byte[] blob = null;

            byte[]    data            = Convert.FromBase64String(challengeString);
            AsnReader reader          = new AsnReader(data, AsnEncodingRules.DER);
            AsnReader challengeReader = reader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp));

            // NegTokenResp::= SEQUENCE {
            //    negState[0] ENUMERATED {
            //        accept - completed(0),
            //        accept - incomplete(1),
            //        reject(2),
            //        request - mic(3)
            //    } OPTIONAL,
            // --REQUIRED in the first reply from the target
            //    supportedMech[1] MechType OPTIONAL,
            // --present only in the first reply from the target
            // responseToken[2] OCTET STRING  OPTIONAL,
            // mechListMIC[3] OCTET STRING  OPTIONAL,
            // ...
            // }

            challengeReader = challengeReader.ReadSequence();
            while (challengeReader.HasData)
            {
                Asn1Tag tag = challengeReader.PeekTag();
                if (tag.TagClass == TagClass.ContextSpecific)
                {
                    NegTokenResp dataType      = (NegTokenResp)tag.TagValue;
                    AsnReader    specificValue = new AsnReader(challengeReader.PeekContentBytes(), AsnEncodingRules.DER);

                    switch (dataType)
                    {
                    case NegTokenResp.NegState:
                        state = specificValue.ReadEnumeratedValue <NegState>();
                        break;

                    case NegTokenResp.SupportedMech:
                        mech = specificValue.ReadObjectIdentifier();
                        break;

                    case NegTokenResp.ResponseToken:
                        blob = specificValue.ReadOctetString();
                        break;

                    default:
                        // Ignore everything else
                        break;
                    }
                }

                challengeReader.ReadEncodedValue();
            }

            if (Diag)
            {
                Console.WriteLine("Negotiate challenege: {0} - {1} in {2}", challengeString, mech, state);
            }

            // Mechanism should be set on first message. That means always
            // as NTLM has only one challenege message.
            if (!NtlmOid.Equals(mech))
            {
                throw new NotSupportedException($"'{mech}' mechanism is not supported");
            }


            if (state != NegState.Unknown && state != NegState.AcceptIncomplete)
            {
                // If state was set, it should be AcceptIncomplete for us to proseed.
                return("");
            }

            if (blob?.Length > 0)
            {
                // Process decoded NTLM blob.
                byte[] response = ProcessChallengeMessage(blob);
                if (response?.Length > 0)
                {
                    AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);

                    using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp)))
                    {
                        writer.PushSequence();
                        using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechToken)))
                        {
                            writer.WriteOctetString(response);
                        }

                        writer.PopSequence();
                    }

                    return("Negotiate " + Convert.ToBase64String(writer.Encode(), Base64FormattingOptions.None));
                }
            }

            return("");
        }