Beispiel #1
0
        public static void PeekEncodedValue_Primitive()
        {
            const string EncodedContents = "010203040506";
            const string EncodedValue    = "0406" + EncodedContents;

            byte[] data = (EncodedValue + "0500").HexToByteArray();

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

            Assert.Equal(EncodedValue, reader.PeekEncodedValue().ByteArrayToHex());

            // It's Peek, so it's reproducible.
            Assert.Equal(EncodedValue, reader.PeekEncodedValue().ByteArrayToHex());
        }
Beispiel #2
0
        public virtual unsafe void ImportRSAPrivateKey(ReadOnlySpan <byte> source, out int bytesRead)
        {
            fixed(byte *ptr = &MemoryMarshal.GetReference(source))
            {
                using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
                {
                    AsnReader             reader     = new AsnReader(manager.Memory, AsnEncodingRules.BER);
                    ReadOnlyMemory <byte> firstValue = reader.PeekEncodedValue();
                    int localRead = firstValue.Length;

                    AlgorithmIdentifierAsn ignored = default;
                    RSAKeyFormatHelper.FromPkcs1PrivateKey(firstValue, ignored, out RSAParameters rsaParameters);

                    fixed(byte *dPin = rsaParameters.D)
                    fixed(byte *pPin    = rsaParameters.P)
                    fixed(byte *qPin    = rsaParameters.Q)
                    fixed(byte *dpPin   = rsaParameters.DP)
                    fixed(byte *dqPin   = rsaParameters.DQ)
                    fixed(byte *qInvPin = rsaParameters.InverseQ)
                    {
                        try
                        {
                            ImportParameters(rsaParameters);
                        }
                        finally
                        {
                            ClearPrivateParameters(rsaParameters);
                        }
                    }

                    bytesRead = localRead;
                }
            }
        }
Beispiel #3
0
        public static void PeekEncodedValue_ExtremelyNested(bool fullArray)
        {
            byte[] dataBytes = new byte[4 * 16384];

            // For a full array this will build 2^14 nested indefinite length values.
            // PeekEncodedValue should return the whole array.
            int end            = dataBytes.Length / 2;
            int expectedLength = dataBytes.Length;

            if (!fullArray)
            {
                // Use 3/4 of what's available, just to prove we're not counting from the end.
                // So with "full" being a nesting value 16384 this will use 12288, and
                // PeekEncodedValue should give us back 48k, not 64k.
                end            = end / 4 * 3;
                expectedLength = 2 * end;
            }

            for (int i = 0; i < end; i += 2)
            {
                // Context-Specific 0 [Constructed]
                dataBytes[i] = 0xA0;
                // Indefinite length
                dataBytes[i + 1] = 0x80;
            }

            AsnReader             reader   = new AsnReader(dataBytes, AsnEncodingRules.BER);
            ReadOnlyMemory <byte> contents = reader.PeekEncodedValue();

            Assert.Equal(expectedLength, contents.Length);
            Assert.True(Unsafe.AreSame(ref dataBytes[0], ref contents.Span.DangerousGetPinnableReference()));
        }
Beispiel #4
0
            public override unsafe void ImportRSAPublicKey(ReadOnlySpan <byte> source, out int bytesRead)
            {
                ThrowIfDisposed();

                fixed(byte *ptr = &MemoryMarshal.GetReference(source))
                {
                    using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
                    {
                        AsnReader             reader       = new AsnReader(manager.Memory, AsnEncodingRules.BER);
                        ReadOnlyMemory <byte> firstElement = reader.PeekEncodedValue();

                        SubjectPublicKeyInfoAsn spki = new SubjectPublicKeyInfoAsn
                        {
                            Algorithm = new AlgorithmIdentifierAsn
                            {
                                Algorithm  = new Oid(Oids.Rsa),
                                Parameters = AlgorithmIdentifierAsn.ExplicitDerNull,
                            },
                            SubjectPublicKey = firstElement,
                        };

                        using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
                        {
                            spki.Encode(writer);
                            ImportSubjectPublicKeyInfo(writer.EncodeAsSpan(), out _);
                        }

                        bytesRead = firstElement.Length;
                    }
                }
            }
Beispiel #5
0
        public static ReadOnlyMemory <byte> DecodeOctetStringAsMemory(ReadOnlyMemory <byte> encodedOctetString)
        {
            AsnReader reader = new AsnReader(encodedOctetString, AsnEncodingRules.BER);

            if (reader.PeekEncodedValue().Length != encodedOctetString.Length)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            // Almost everything in X.509 is DER-encoded, which means Octet String values are
            // encoded as a primitive (non-segmented)
            //
            // Even in BER Octet Strings are usually encoded as a primitive.
            if (reader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> primitiveContents))
            {
                return(primitiveContents);
            }

            byte[] tooBig = new byte[encodedOctetString.Length];

            if (reader.TryCopyOctetStringBytes(tooBig, out int bytesWritten))
            {
                return(tooBig.AsMemory(0, bytesWritten));
            }

            Debug.Fail("TryCopyOctetStringBytes failed with an over-allocated array");
            throw new CryptographicException();
        }
Beispiel #6
0
        public override unsafe void ImportRSAPublicKey(ReadOnlySpan <byte> source, out int bytesRead)
        {
            ThrowIfDisposed();

            fixed(byte *ptr = &MemoryMarshal.GetReference(source))
            {
                using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
                {
                    AsnReader             reader       = new AsnReader(manager.Memory, AsnEncodingRules.BER);
                    ReadOnlyMemory <byte> firstElement = reader.PeekEncodedValue();

                    SafeRsaHandle key = Interop.Crypto.DecodeRsaPublicKey(firstElement.Span);

                    Interop.Crypto.CheckValidOpenSslHandle(key);

                    FreeKey();
                    _key = new Lazy <SafeRsaHandle>(key);

                    // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere
                    // with the already loaded key.
                    ForceSetKeySize(BitsPerByte * Interop.Crypto.RsaSize(key));

                    bytesRead = firstElement.Length;
                }
            }
        }
        private static bool TryDecode(
            ReadOnlyMemory <byte> source,
            bool ownsMemory,
            out Rfc3161TstInfo tstInfo,
            out int bytesConsumed,
            out byte[] copiedBytes)
        {
            // https://tools.ietf.org/html/rfc3161#section-2.4.2
            // The eContent SHALL be the DER-encoded value of TSTInfo.
            AsnReader reader = new AsnReader(source, AsnEncodingRules.DER);

            try
            {
                ReadOnlyMemory <byte> firstElement = reader.PeekEncodedValue();

                if (ownsMemory)
                {
                    copiedBytes = null;
                }
                else
                {
                    // Copy the data so no ReadOnlyMemory values are pointing back to user data.
                    copiedBytes  = firstElement.ToArray();
                    firstElement = copiedBytes;
                }

                Rfc3161TstInfo parsedInfo = AsnSerializer.Deserialize <Rfc3161TstInfo>(
                    firstElement,
                    AsnEncodingRules.DER);

                // The deserializer doesn't do bounds checks.
                // Micros and Millis are defined as (1..999)
                // Seconds doesn't define that it's bounded by 0,
                // but negative accuracy doesn't make sense.
                //
                // (Reminder to readers: a null int? with an inequality operator
                // has the value false, so if accuracy is missing, or millis or micro is missing,
                // then the respective checks return false and don't throw).
                if (parsedInfo.Accuracy?.Micros > 999 ||
                    parsedInfo.Accuracy?.Micros < 1 ||
                    parsedInfo.Accuracy?.Millis > 999 ||
                    parsedInfo.Accuracy?.Millis < 1 ||
                    parsedInfo.Accuracy?.Seconds < 0)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }

                tstInfo       = parsedInfo;
                bytesConsumed = firstElement.Length;
                return(true);
            }
            catch (CryptographicException)
            {
                tstInfo       = null;
                bytesConsumed = 0;
                copiedBytes   = null;
                return(false);
            }
        }
        public static T Deserialize <T>(ReadOnlyMemory <byte> source, AsnEncodingRules ruleSet, out int bytesRead)
        {
            Deserializer          deserializer = GetDeserializer(typeof(T), null);
            AsnReader             reader       = new AsnReader(source, ruleSet);
            ReadOnlyMemory <byte> firstElement = reader.PeekEncodedValue();

            T t = (T)deserializer(reader);

            bytesRead = firstElement.Length;
            return(t);
        }
Beispiel #9
0
        public static void PeekContentSpan_Indefinite()
        {
            const string EncodedContents = "040101" + "04050203040506";
            const string EncodedValue    = "2480" + EncodedContents + "0000";

            byte[] data = (EncodedValue + "0500").HexToByteArray();

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

            Assert.Equal(EncodedContents, reader.PeekContentBytes().ByteArrayToHex());

            // It's Peek, so it's reproducible.
            Assert.Equal(EncodedValue, reader.PeekEncodedValue().ByteArrayToHex());
        }
Beispiel #10
0
            public override unsafe void ImportRSAPublicKey(ReadOnlySpan <byte> source, out int bytesRead)
            {
                ThrowIfDisposed();

                fixed(byte *ptr = &MemoryMarshal.GetReference(source))
                {
                    using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
                    {
                        ReadOnlyMemory <byte> subjectPublicKey;
                        try
                        {
                            AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER);
                            subjectPublicKey = reader.PeekEncodedValue();
                        }
                        catch (AsnContentException e)
                        {
                            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
                        }

                        // Decoding the key on Android requires the encoded SubjectPublicKeyInfo,
                        // not just the SubjectPublicKey, so we construct one.
                        SubjectPublicKeyInfoAsn spki = new SubjectPublicKeyInfoAsn
                        {
                            Algorithm = new AlgorithmIdentifierAsn
                            {
                                Algorithm  = Oids.Rsa,
                                Parameters = AlgorithmIdentifierAsn.ExplicitDerNull,
                            },
                            SubjectPublicKey = subjectPublicKey,
                        };

                        AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
                        spki.Encode(writer);

                        SafeRsaHandle key = Interop.AndroidCrypto.DecodeRsaSubjectPublicKeyInfo(writer.Encode());
                        if (key is null || key.IsInvalid)
                        {
                            key?.Dispose();
                            throw new CryptographicException();
                        }

                        FreeKey();
                        _key = new Lazy <SafeRsaHandle>(key);
                        SetKeySizeFromHandle(key);

                        bytesRead = subjectPublicKey.Length;
                    }
                }
            }
Beispiel #11
0
 internal static unsafe ECParameters FromECPrivateKey(ReadOnlySpan <byte> key, out int bytesRead)
 {
     fixed(byte *ptr = &MemoryMarshal.GetReference(key))
     {
         using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, key.Length))
         {
             AsnReader reader                  = new AsnReader(manager.Memory, AsnEncodingRules.BER);
             AlgorithmIdentifierAsn algId      = default;
             ReadOnlyMemory <byte>  firstValue = reader.PeekEncodedValue();
             FromECPrivateKey(firstValue, algId, out ECParameters ret);
             bytesRead = firstValue.Length;
             return(ret);
         }
     }
 }
Beispiel #12
0
        public static void PeekEncodedValue_Corrupt_Throws()
        {
            const string EncodedContents = "040101" + "04050203040506";
            // Constructed bit isn't set, so indefinite length is invalid.
            const string EncodedValue = "0480" + EncodedContents + "0000";

            byte[] data = (EncodedValue + "0500").HexToByteArray();

            Assert.Throws <CryptographicException>(
                () =>
            {
                AsnReader reader = new AsnReader(data, AsnEncodingRules.BER);
                reader.PeekEncodedValue();
            });
        }
Beispiel #13
0
        public virtual unsafe void ImportRSAPublicKey(ReadOnlySpan <byte> source, out int bytesRead)
        {
            fixed(byte *ptr = &MemoryMarshal.GetReference(source))
            {
                using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
                {
                    AsnReader             reader     = new AsnReader(manager.Memory, AsnEncodingRules.BER);
                    ReadOnlyMemory <byte> firstValue = reader.PeekEncodedValue();
                    int localRead = firstValue.Length;

                    AlgorithmIdentifierAsn ignored = default;
                    RSAKeyFormatHelper.ReadRsaPublicKey(firstValue, ignored, out RSAParameters rsaParameters);

                    ImportParameters(rsaParameters);

                    bytesRead = localRead;
                }
            }
        }
Beispiel #14
0
        protected void ParsePkcs12(byte[] data)
        {
            // RFC7292 specifies BER instead of DER
            AsnReader             reader      = new AsnReader(data, AsnEncodingRules.BER);
            ReadOnlyMemory <byte> encodedData = reader.PeekEncodedValue();

            // Windows compatibility: Ignore trailing data.
            if (encodedData.Length != data.Length)
            {
                reader = new AsnReader(encodedData, AsnEncodingRules.BER);
            }

            PfxAsn.Decode(reader, out PfxAsn pfxAsn);

            if (pfxAsn.AuthSafe.ContentType != Oids.Pkcs7Data)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            _pfxAsn = pfxAsn;
        }
Beispiel #15
0
        public static void PeekEncodedValue_InvalidLength()
        {
            byte[] badLength = "04040203".HexToByteArray();

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

            Assert.Throws <CryptographicException>(() => reader.PeekEncodedValue());
            Assert.Throws <CryptographicException>(() => reader.ReadEncodedValue());

            Assert.Throws <CryptographicException>(
                () =>
            {
                AsnValueReader valueReader = new AsnValueReader(badLength, AsnEncodingRules.BER);
                valueReader.PeekEncodedValue();
            });
            Assert.Throws <CryptographicException>(
                () =>
            {
                AsnValueReader valueReader = new AsnValueReader(badLength, AsnEncodingRules.BER);
                valueReader.ReadEncodedValue();
            });
        }
        public static void PeekEncodedValue_InvalidLength()
        {
            byte[] badLength = "04040203".HexToByteArray();

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

            Assert.Throws <AsnContentException>(() => reader.PeekEncodedValue());
            Assert.Throws <AsnContentException>(() => reader.ReadEncodedValue());

            Assert.False(
                AsnDecoder.TryReadEncodedValue(
                    badLength,
                    AsnEncodingRules.BER,
                    out Asn1Tag tag,
                    out int contentOffset,
                    out int contentLength,
                    out int bytesConsumed));

            Assert.Equal(0, contentOffset);
            Assert.Equal(0, contentLength);
            Assert.Equal(0, bytesConsumed);
            Assert.Equal(default(Asn1Tag), tag);
        }
        public static bool TryDecode(
            ReadOnlyMemory <byte> encodedBytes,
            out Rfc3161TimestampRequest request,
            out int bytesConsumed)
        {
            try
            {
                // RFC 3161 doesn't have a concise statement that TimeStampReq will
                // be DER encoded, but under the email protocol (3.1), file protocol (3.2),
                // socket protocol (3.3) and HTTP protocol (3.4) they all say DER for the
                // transmission.
                //
                // Since nothing says BER, assume DER only.
                const AsnEncodingRules RuleSet = AsnEncodingRules.DER;

                AsnReader             reader       = new AsnReader(encodedBytes, RuleSet);
                ReadOnlyMemory <byte> firstElement = reader.PeekEncodedValue();

                var req = AsnSerializer.Deserialize <Rfc3161TimeStampReq>(firstElement, RuleSet);

                request = new Rfc3161TimestampRequest
                {
                    _parsedData   = req,
                    _encodedBytes = firstElement.ToArray(),
                };

                bytesConsumed = firstElement.Length;
                return(true);
            }
            catch (CryptographicException)
            {
            }

            request       = null;
            bytesConsumed = 0;
            return(false);
        }
Beispiel #18
0
        public static ReadOnlyMemory <byte> DecodeOctetString(ReadOnlyMemory <byte> encodedOctetString)
        {
            AsnReader reader = new AsnReader(encodedOctetString, AsnEncodingRules.BER);

            if (reader.PeekEncodedValue().Length != encodedOctetString.Length)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            if (reader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> primitiveContents))
            {
                return(primitiveContents);
            }

            byte[] tooBig = new byte[encodedOctetString.Length];

            if (reader.TryCopyOctetStringBytes(tooBig, out int bytesWritten))
            {
                return(tooBig.AsMemory(0, bytesWritten));
            }

            Debug.Fail("TryCopyOctetStringBytes failed with an over-allocated array");
            throw new CryptographicException();
        }
Beispiel #19
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());
            }
        }
Beispiel #20
0
        public static Pkcs12Info Decode(
            ReadOnlyMemory <byte> encodedBytes,
            out int bytesConsumed,
            bool skipCopy = false)
        {
            AsnReader reader = new AsnReader(encodedBytes, AsnEncodingRules.BER);

            // Trim it to the first value
            encodedBytes = reader.PeekEncodedValue();

            ReadOnlyMemory <byte> maybeCopy = skipCopy ? encodedBytes : encodedBytes.ToArray();
            PfxAsn pfx = PfxAsn.Decode(maybeCopy, AsnEncodingRules.BER);

            // https://tools.ietf.org/html/rfc7292#section-4 only defines version 3.
            if (pfx.Version != 3)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            ReadOnlyMemory <byte> authSafeBytes = ReadOnlyMemory <byte> .Empty;
            Pkcs12IntegrityMode   mode          = Pkcs12IntegrityMode.Unknown;

            if (pfx.AuthSafe.ContentType == Oids.Pkcs7Data)
            {
                authSafeBytes = PkcsHelpers.DecodeOctetStringAsMemory(pfx.AuthSafe.Content);

                if (pfx.MacData.HasValue)
                {
                    mode = Pkcs12IntegrityMode.Password;
                }
                else
                {
                    mode = Pkcs12IntegrityMode.None;
                }
            }
            else if (pfx.AuthSafe.ContentType == Oids.Pkcs7Signed)
            {
                SignedDataAsn signedData = SignedDataAsn.Decode(pfx.AuthSafe.Content, AsnEncodingRules.BER);

                mode = Pkcs12IntegrityMode.PublicKey;

                if (signedData.EncapContentInfo.ContentType == Oids.Pkcs7Data)
                {
                    authSafeBytes = signedData.EncapContentInfo.Content.GetValueOrDefault();
                }

                if (pfx.MacData.HasValue)
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }
            }

            if (mode == Pkcs12IntegrityMode.Unknown)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

            List <ContentInfoAsn> authSafeData   = new List <ContentInfoAsn>();
            AsnReader             authSafeReader = new AsnReader(authSafeBytes, AsnEncodingRules.BER);
            AsnReader             sequenceReader = authSafeReader.ReadSequence();

            authSafeReader.ThrowIfNotEmpty();
            while (sequenceReader.HasData)
            {
                ContentInfoAsn.Decode(sequenceReader, out ContentInfoAsn contentInfo);
                authSafeData.Add(contentInfo);
            }

            ReadOnlyCollection <Pkcs12SafeContents> authSafe;

            if (authSafeData.Count == 0)
            {
                authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(Array.Empty <Pkcs12SafeContents>());
            }
            else
            {
                Pkcs12SafeContents[] contentsArray = new Pkcs12SafeContents[authSafeData.Count];

                for (int i = 0; i < contentsArray.Length; i++)
                {
                    contentsArray[i] = new Pkcs12SafeContents(authSafeData[i]);
                }

                authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(contentsArray);
            }

            bytesConsumed = encodedBytes.Length;

            return(new Pkcs12Info
            {
                AuthenticatedSafe = authSafe,
                IntegrityMode = mode,
                _decoded = pfx,
                _authSafeContents = authSafeBytes,
            });
        }
        private bool ProcessResponse(
            ReadOnlyMemory <byte> source,
            out Rfc3161TimestampToken token,
            out Rfc3161RequestResponseStatus status,
            out int bytesConsumed,
            bool shouldThrow)
        {
            status = Rfc3161RequestResponseStatus.Unknown;
            token  = null;

            Rfc3161TimeStampResp resp;

            try
            {
                AsnReader reader         = new AsnReader(source, AsnEncodingRules.DER);
                int       localBytesRead = reader.PeekEncodedValue().Length;

                Rfc3161TimeStampResp.Decode(reader, out resp);
                bytesConsumed = localBytesRead;
            }
            catch (CryptographicException) when(!shouldThrow)
            {
                bytesConsumed = 0;
                status        = Rfc3161RequestResponseStatus.DoesNotParse;
                return(false);
            }

            // bytesRead will be set past this point

            PkiStatus pkiStatus = (PkiStatus)resp.Status.Status;

            if (pkiStatus != PkiStatus.Granted &&
                pkiStatus != PkiStatus.GrantedWithMods)
            {
                if (shouldThrow)
                {
                    throw new CryptographicException(
                              SR.Format(
                                  SR.Cryptography_TimestampReq_Failure,
                                  pkiStatus,
                                  resp.Status.FailInfo.GetValueOrDefault()));
                }

                status = Rfc3161RequestResponseStatus.RequestFailed;
                return(false);
            }

            if (!Rfc3161TimestampToken.TryDecode(resp.TimeStampToken.GetValueOrDefault(), out token, out _))
            {
                if (shouldThrow)
                {
                    throw new CryptographicException(SR.Cryptography_TimestampReq_BadResponse);
                }

                bytesConsumed = 0;
                status        = Rfc3161RequestResponseStatus.DoesNotParse;
                return(false);
            }

            status = ValidateResponse(token, shouldThrow);
            return(status == Rfc3161RequestResponseStatus.Accepted);
        }