/// <summary> /// decoding the data with security provider /// </summary> /// <param name="data"> /// a bytes data that contains the data to be decoded with security provider. /// </param> /// <returns> /// a bytes data that contains the decoded data. /// </returns> /// <exception cref="ArgumentNullException"> /// thrown when data is null. /// </exception> public override byte[] Decode(byte[] data) { if (data == null) { throw new ArgumentNullException("data"); } // if the ssl stream is authenticated, but user do not want to encrypted data // directly return the plaintext data. if (this.sslStream.IsAuthenticated && !this.UsingMessageSecurity) { this.consumedData = false; return(data); } this.streamProxy.AddReceivedData(data); this.consumedData = true; this.consumedLength = data.Length; // if ssl is not authenticated, and ssl do not need to wait for data // that is, data is enough for current ssl, must wait for it to consumed it. while (!this.sslStream.IsAuthenticated && !this.streamProxy.WaitingForDataComing) { Thread.Sleep(MILLI_SECONDS_TO_WAIT_SSL_CONSUME_DATA); } AdtsLdapSslTlsSecurityHeader header = new AdtsLdapSslTlsSecurityHeader(); header.FromBytes(this.streamProxy.ReceivedBuffer.Peek(AdtsLdapSslTlsSecurityHeader.SIZE_OF_HEADER)); // if data is received enough to decode. if (this.sslStream.IsAuthenticated && header.IsValid(this.streamProxy.ReceivedBuffer.Length)) { byte[] decryptedData = new byte[header.Length]; this.sslStream.Read(decryptedData, 0, decryptedData.Length); return(decryptedData); } return(new byte[0]); }
/// <summary> /// This method encapsulates LdapV2Decoder and LdapV3Decoder because the incoming packets may be /// LDAP v2 or v3 packets, the decoding may require both decoders if the LDAP version that client uses /// is not clear. /// </summary> /// <param name="endPoint">The end point of the client.</param> /// <param name="messageBytes">The message bytes that contains the packet data.</param> /// <param name="consumedLength">Consumed length.</param> /// <param name="expectedLength"> /// Indicates expected length if the message bytes doesn't all packet data. /// </param> /// <returns>Decoded packets.</returns> internal override StackPacket[] DecodeLdapPacketCallBack( object endPoint, byte[] messageBytes, out int consumedLength, out int expectedLength) { // Get packet data, start decoding. IPEndPoint remote = (IPEndPoint)endPoint; AdtsLdapContext context = GetContext(remote, this.server.IsTcp); byte[] data = messageBytes; // decode messageBytes if needed if (context != null && messageBytes != null) { // if security is not init, and the package is SslHandshake, init security. if (context.Security == null) { AdtsLdapSslTlsSecurityHeader header = new AdtsLdapSslTlsSecurityHeader(); header.FromBytes(messageBytes); if (header.IsSslHandShake) { this.server.SslStartup(context); } } // decode messageBytes with security. if (context.Security != null) { data = this.server.Decrypt(context, messageBytes); } } byte[] packetData = this.GetSinglePacketData(data, out consumedLength, out expectedLength); // add the comsumed length of security decorder if (context != null && context.Security != null && context.Security.ConsumedData) { consumedLength = context.Security.ConsumedLength; } if (packetData == null) { return(null); } // New connection. Try both LDAP v2 and v3 decoders. Note that for requests that don't have version // context(e.g., UDP search requests), LDAP v3 is used by default. AdtsLdapPacket packet = null; if (context == null) { context = new AdtsLdapContext(AdtsLdapVersion.V3, remote); packet = this.decoderv3.ParseAdtsLdapPacket( this.decoderv3.AuthenticateMessage(packetData), context); // synchronize the message ID with newly received packet. context.MessageId = packet.messageId; // Check BindRequestPacket, normally it's the first message from client in which // contains the LDAP version. And since LDAP v3 decoder can decode LDAP v2 messages // without any exception, we need to check into the 'version' variable in the request. AdtsBindRequestPacket bindRequestPacket = packet as AdtsBindRequestPacket; if (bindRequestPacket != null) { LdapV3.BindRequest bindRequest = (LdapV3.BindRequest)bindRequestPacket.GetInnerRequestOrResponse(); // Version doesn't match. Decode again with LDAP v2 decoder and update context version. if ((AdtsLdapVersion)bindRequest.version.Value == AdtsLdapVersion.V2) { packet = this.decoderv2.ParseAdtsLdapPacket( this.decoderv2.AuthenticateMessage(packetData), context); context.ClientVersion = context.ServerVersion = AdtsLdapVersion.V2; } } // Add context. this.server.ContextManager.AddContext(context, this.server.IsTcp); } else { if (context.ClientVersion == AdtsLdapVersion.V2) { packet = this.decoderv2.ParseAdtsLdapPacket( this.decoderv2.AuthenticateMessage(packetData), context); } else { packet = this.decoderv3.ParseAdtsLdapPacket( this.decoderv3.AuthenticateMessage(packetData), context); } // synchronize the message ID with newly received packet. context.MessageId = packet.messageId; } return(new StackPacket[] { packet }); }
/// <summary> /// decoding the data with security provider /// </summary> /// <param name="data"> /// a bytes data that contains the data to be decoded with security provider. /// </param> /// <returns> /// a bytes data that contains the decoded data. /// </returns> /// <exception cref="ArgumentNullException"> /// thrown when data is null. /// </exception> public override byte[] Decode(byte[] data) { if (data == null) { throw new ArgumentNullException("data"); } // if the ssl stream is authenticated, but user do not want to encrypted data // directly return the plaintext data. if (this.sslStream.IsAuthenticated && !this.UsingMessageSecurity) { this.consumedData = false; return data; } this.streamProxy.AddReceivedData(data); this.consumedData = true; this.consumedLength = data.Length; // if ssl is not authenticated, and ssl do not need to wait for data // that is, data is enough for current ssl, must wait for it to consumed it. while (!this.sslStream.IsAuthenticated && !this.streamProxy.WaitingForDataComing) { Thread.Sleep(MILLI_SECONDS_TO_WAIT_SSL_CONSUME_DATA); } AdtsLdapSslTlsSecurityHeader header = new AdtsLdapSslTlsSecurityHeader(); header.FromBytes(this.streamProxy.ReceivedBuffer.Peek(AdtsLdapSslTlsSecurityHeader.SIZE_OF_HEADER)); // if data is received enough to decode. if (this.sslStream.IsAuthenticated && header.IsValid(this.streamProxy.ReceivedBuffer.Length)) { byte[] decryptedData = new byte[header.Length]; this.sslStream.Read(decryptedData, 0, decryptedData.Length); return decryptedData; } return new byte[0]; }
/// <summary> /// This method encapsulates LdapV2Decoder and LdapV3Decoder because the incoming packets may be /// LDAP v2 or v3 packets, the decoding may require both decoders if the LDAP version that client uses /// is not clear. /// </summary> /// <param name="endPoint">The end point of the client.</param> /// <param name="messageBytes">The message bytes that contains the packet data.</param> /// <param name="consumedLength">Consumed length.</param> /// <param name="expectedLength"> /// Indicates expected length if the message bytes doesn't all packet data. /// </param> /// <returns>Decoded packets.</returns> internal override StackPacket[] DecodeLdapPacketCallBack( object endPoint, byte[] messageBytes, out int consumedLength, out int expectedLength) { // Get packet data, start decoding. IPEndPoint remote = (IPEndPoint)endPoint; AdtsLdapContext context = GetContext(remote, this.server.IsTcp); byte[] data = messageBytes; // decode messageBytes if needed if (context != null && messageBytes != null) { // if security is not init, and the package is SslHandshake, init security. if (context.Security == null) { AdtsLdapSslTlsSecurityHeader header = new AdtsLdapSslTlsSecurityHeader(); header.FromBytes(messageBytes); if (header.IsSslHandShake) { this.server.SslStartup(context); } } // decode messageBytes with security. if (context.Security != null) { data = this.server.Decrypt(context, messageBytes); } } byte[] packetData = this.GetSinglePacketData(data, out consumedLength, out expectedLength); // add the comsumed length of security decorder if (context != null && context.Security != null && context.Security.ConsumedData) { consumedLength = context.Security.ConsumedLength; } if (packetData == null) { return null; } // New connection. Try both LDAP v2 and v3 decoders. Note that for requests that don't have version // context(e.g., UDP search requests), LDAP v3 is used by default. AdtsLdapPacket packet = null; if (context == null) { context = new AdtsLdapContext(AdtsLdapVersion.V3, remote); packet = this.decoderv3.ParseAdtsLdapPacket( this.decoderv3.AuthenticateMessage(packetData), context); // synchronize the message ID with newly received packet. context.MessageId = packet.messageId; // Check BindRequestPacket, normally it's the first message from client in which // contains the LDAP version. And since LDAP v3 decoder can decode LDAP v2 messages // without any exception, we need to check into the 'version' variable in the request. AdtsBindRequestPacket bindRequestPacket = packet as AdtsBindRequestPacket; if (bindRequestPacket != null) { LdapV3.BindRequest bindRequest = (LdapV3.BindRequest)bindRequestPacket.GetInnerRequestOrResponse(); // Version doesn't match. Decode again with LDAP v2 decoder and update context version. if ((AdtsLdapVersion)bindRequest.version.Value == AdtsLdapVersion.V2) { packet = this.decoderv2.ParseAdtsLdapPacket( this.decoderv2.AuthenticateMessage(packetData), context); context.ClientVersion = context.ServerVersion = AdtsLdapVersion.V2; } } // Add context. this.server.ContextManager.AddContext(context, this.server.IsTcp); } else { if (context.ClientVersion == AdtsLdapVersion.V2) { packet = this.decoderv2.ParseAdtsLdapPacket( this.decoderv2.AuthenticateMessage(packetData), context); } else { packet = this.decoderv3.ParseAdtsLdapPacket( this.decoderv3.AuthenticateMessage(packetData), context); } // synchronize the message ID with newly received packet. context.MessageId = packet.messageId; } return new StackPacket[] { packet }; }