/// <summary>
            /// Begins processing an incoming request.
            /// </summary>
            /// <param name="context">The security context for the request</param>
            /// <param name="requestData">The request data.</param>
            /// <returns>
            /// The result object that is used to call the EndProcessRequest method.
            /// </returns>
            public IAsyncResult BeginProcessRequest(
                SecureChannelContext context,
                byte[] requestData)
            {
                m_context = context;

                try
                {
                    // decoding incoming message.
                    m_request = BinaryDecoder.DecodeMessage(requestData, null, m_endpoint.MessageContext) as IServiceRequest;

                    // find service.
                    m_service = m_endpoint.FindService(m_request.TypeId);

                    if (m_service == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadServiceUnsupported, "'{0}' is an unrecognized service type.", m_request.TypeId);
                    }

                    // queue request.
                    m_endpoint.ServerForContext.ScheduleIncomingRequest(this);
                }
                catch (Exception e)
                {
                    m_error    = e;
                    m_response = SaveExceptionAsResponse(e);

                    // operation completed.
                    OperationCompleted();
                }

                return(this);
            }
Beispiel #2
0
        public IServiceResponse EndSendRequest(IAsyncResult result)
        {
            AsyncResult result2 = result as AsyncResult;

            if (result2 == null)
            {
                throw new ArgumentException("Invalid result object passed.", nameof(result));
            }

            try
            {
                result2.WaitForComplete();
                if (result2.Response != null)
                {
                    Stream responseContent = result2.Response.Content.ReadAsStreamAsync().Result;
                    return(BinaryDecoder.DecodeMessage(responseContent, null, m_quotas.MessageContext) as IServiceResponse);
                }
            }
            catch (Exception ex)
            {
                Utils.Trace("Exception reading HTTPS response: " + ex.Message);
                result2.Exception = ex;
            }
            return(result2 as IServiceResponse);
        }
Beispiel #3
0
        /// <summary>
        /// Sends a request over the secure channel.
        /// </summary>
        public IServiceResponse SendRequest(IServiceRequest request)
        {
            if (m_wcfBypassChannel != null)
            {
                return(m_wcfBypassChannel.SendRequest(request));
            }

            byte[] requestMessage = BinaryEncoder.EncodeMessage(request, m_messageContext);
            InvokeServiceResponseMessage responseMessage = InvokeService(new InvokeServiceMessage(requestMessage));

            return((IServiceResponse)BinaryDecoder.DecodeMessage(responseMessage.InvokeServiceResponse, null, m_messageContext));
        }
Beispiel #4
0
        /// <summary>
        /// Completes an asynchronous operation to send a request over the secure channel.
        /// </summary>
        public IServiceResponse EndSendRequest(IAsyncResult result)
        {
            AsyncResult result2 = result as AsyncResult;

            if (result2 == null)
            {
                throw new ArgumentException("Invalid result object passed.", "result");
            }

            result2.WaitForComplete();

            HttpWebResponse response = (HttpWebResponse)result2.WebRequest.EndGetResponse(result2.InnerResult);

            Stream       istrm = response.GetResponseStream();
            MemoryStream mstrm = new MemoryStream();

            int bytesRead = 0;

            byte[] buffer = new byte[4096];

            do
            {
                bytesRead = istrm.Read(buffer, 0, buffer.Length);
                mstrm.Write(buffer, 0, bytesRead);
            } while (bytesRead != 0);

            mstrm.Position = 0;
            istrm.Close();

            IEncodeable message = null;

            if (m_settings.Configuration.UseBinaryEncoding)
            {
                message = BinaryDecoder.DecodeMessage(mstrm, null, this.MessageContext);
            }
            else
            {
                string responseType = result2.Request.GetType().FullName.Replace("Request", "Response");

                message = ReadSoapMessage(
                    mstrm,
                    responseType.Substring("Opc.Ua.".Length),
                    Type.GetType(responseType),
                    this.MessageContext);
            }

            istrm.Close();

            return(message as IServiceResponse);
        }
Beispiel #5
0
        /// <summary>
        /// Completes an asynchronous operation to send a request over the secure channel.
        /// </summary>
        public IServiceResponse EndSendRequest(IAsyncResult result)
        {
            if (m_wcfBypassChannel != null)
            {
                return(m_wcfBypassChannel.EndSendRequest(result));
            }

#if MANAGE_CHANNEL_THREADS
            return(SendRequestAsyncResult.WaitForComplete(result));
#else
            InvokeServiceResponseMessage responseMessage = EndInvokeService(result);
            return((IServiceResponse)BinaryDecoder.DecodeMessage(responseMessage.InvokeServiceResponse, null, m_messageContext));
#endif
        }
/// <summary>
/// Completes the _NAME_ service.
/// </summary>
    public _NAME_Response End_NAME_(IAsyncResult result)
    {
        InvokeServiceResponseMessage response = null;

        try
        {
            response = Channel.EndInvokeService(result);
        }
        catch (FaultException <ServiceFault> e)
        {
            throw HandleSoapFault(e);
        }

        CheckForFault(response);

        return((_NAME_Response)BinaryDecoder.DecodeMessage(response.InvokeServiceResponse, typeof(_NAME_Response), CreateContext()));
    }
Beispiel #7
0
        /// <summary>
        /// Dispatches an incoming binary encoded request.
        /// </summary>
        /// <param name="request">Request.</param>
        /// <returns>Invoke service response message.</returns>
        public virtual InvokeServiceResponseMessage InvokeService(InvokeServiceMessage request)
        {
            IServiceRequest  decodedRequest = null;
            IServiceResponse response       = null;

            // create context for request and reply.
            ServiceMessageContext context = MessageContext;

            try
            {
                // check for null.
                if (request == null || request.InvokeServiceRequest == null)
                {
                    throw new ServiceResultException(StatusCodes.BadDecodingError, Utils.Format("Null message cannot be processed."));
                }

                // decoding incoming message.
                decodedRequest =
                    BinaryDecoder.DecodeMessage(request.InvokeServiceRequest, null, context) as IServiceRequest;

                // invoke service.
                response = ProcessRequest(decodedRequest);

                // encode response.
                InvokeServiceResponseMessage outgoing = new InvokeServiceResponseMessage();
                outgoing.InvokeServiceResponse = BinaryEncoder.EncodeMessage(response, context);
                return(outgoing);
            }
            catch (Exception e)
            {
                // create fault.
                ServiceFault fault = CreateFault(decodedRequest, e);

                // encode fault response.
                if (context == null)
                {
                    context = new ServiceMessageContext();
                }

                InvokeServiceResponseMessage outgoing = new InvokeServiceResponseMessage();
                outgoing.InvokeServiceResponse = BinaryEncoder.EncodeMessage(fault, context);
                return(outgoing);
            }
        }
        /// <inheritdoc/>
        public async Task <IServiceResponse> SendRequestAsync(IServiceRequest request, CancellationToken ct)
        {
            try
            {
                ByteArrayContent content = new ByteArrayContent(BinaryEncoder.EncodeMessage(request, m_quotas.MessageContext));
                content.Headers.ContentType = m_mediaTypeHeaderValue;
                var result = await m_client.PostAsync(m_url, content, ct);

                result.EnsureSuccessStatusCode();
                Stream responseContent = await result.Content.ReadAsStreamAsync();

                return(BinaryDecoder.DecodeMessage(responseContent, null, m_quotas.MessageContext) as IServiceResponse);
            }
            catch (Exception ex)
            {
                Utils.Trace("Exception sending HTTPS request: " + ex.Message);
                throw;
            }
        }
Beispiel #9
0
        static TestStackRequest Decode(byte[] message, ServiceMessageContext context1, bool binary)
        {
            if (binary)
            {
                return((TestStackRequest)BinaryDecoder.DecodeMessage(message, null, context1));
            }
            else
            {
                ServiceMessageContext.ThreadContext = context1;

                MemoryStream      istrm    = new MemoryStream(message);
                XmlReaderSettings settings = new XmlReaderSettings();

                using (XmlReader reader = XmlReader.Create(istrm, settings))
                {
                    DataContractSerializer serializer = new DataContractSerializer(typeof(TestStackRequest));
                    return((TestStackRequest)serializer.ReadObject(reader));
                }
            }
        }
Beispiel #10
0
// ***START***
#if (!OPCUA_EXCLUDE__NAME_)
/// <summary>
/// Invokes the _NAME_ service.
/// </summary>
    public _NAME_Response _NAME_(_NAME_Request request)
    {
        BinaryMessageContext context = CreateContext();

        byte[] buffer = BinaryEncoder.EncodeMessage(request, context);

        InvokeServiceResponseMessage response = null;

        try
        {
            response = Channel.InvokeService(new InvokeServiceMessage(buffer));
        }
        catch (FaultException <ServiceFault> e)
        {
            throw HandleSoapFault(e);
        }

        CheckForFault(response);

        return((_NAME_Response)BinaryDecoder.DecodeMessage(response.InvokeServiceResponse, typeof(_NAME_Response), context));
    }
        /// <summary>
        /// Handles requests arriving from a channel.
        /// </summary>
        public async void SendAsync(HttpContext context)
        {
            IAsyncResult result = null;

            try
            {
                if (m_callback == null)
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.NotImplemented;
                    await context.Response.WriteAsync(string.Empty);

                    return;
                }

                byte[] buffer = new byte[(int)context.Request.ContentLength];
                lock (m_lock)
                {
                    Task <int> task = context.Request.Body.ReadAsync(buffer, 0, (int)context.Request.ContentLength);
                    task.Wait();
                }

                IServiceRequest input = (IServiceRequest)BinaryDecoder.DecodeMessage(buffer, null, m_quotas.MessageContext);

                // extract the JWT token from the HTTP headers.
                if (input.RequestHeader == null)
                {
                    input.RequestHeader = new RequestHeader();
                }

                if (NodeId.IsNull(input.RequestHeader.AuthenticationToken) && input.TypeId != DataTypeIds.CreateSessionRequest)
                {
                    if (context.Request.Headers.Keys.Contains("Authorization"))
                    {
                        foreach (string value in context.Request.Headers["Authorization"])
                        {
                            if (value.StartsWith("Bearer"))
                            {
                                input.RequestHeader.AuthenticationToken = new NodeId(value.Substring("Bearer ".Length).Trim());
                            }
                        }
                    }
                }

                EndpointDescription endpoint = null;

                foreach (var ep in m_descriptions)
                {
                    if (ep.EndpointUrl.StartsWith(Utils.UriSchemeHttps))
                    {
                        endpoint = ep;
                        break;
                    }
                }

                result = m_callback.BeginProcessRequest(
                    m_listenerId,
                    endpoint,
                    input as IServiceRequest,
                    null,
                    null);

                IServiceResponse output = m_callback.EndProcessRequest(result);

                byte[] response = BinaryEncoder.EncodeMessage(output, m_quotas.MessageContext);
                context.Response.ContentLength = response.Length;
                context.Response.ContentType   = context.Request.ContentType;
                context.Response.StatusCode    = (int)HttpStatusCode.OK;
                await context.Response.Body.WriteAsync(response, 0, response.Length);
            }
            catch (Exception e)
            {
                Utils.Trace(e, "HTTPSLISTENER - Unexpected error processing request.");
                context.Response.ContentLength = e.Message.Length;
                context.Response.ContentType   = "text/plain";
                context.Response.StatusCode    = (int)HttpStatusCode.InternalServerError;
                await context.Response.WriteAsync(e.Message);
            }
        }
Beispiel #12
0
        /// <summary>
        /// Handles requests arriving from a channel.
        /// </summary>
        private IAsyncResult BeginProcessRequest(Stream istrm, string action, string securityPolicyUri, object callbackData)
        {
            IAsyncResult result = null;

            try
            {
                if (m_callback != null)
                {
                    string contentType = WebOperationContext.Current.IncomingRequest.ContentType;
                    Uri    uri         = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri;

                    string scheme = uri.Scheme + ":";

                    EndpointDescription endpoint = null;

                    for (int ii = 0; ii < m_descriptions.Count; ii++)
                    {
                        if (m_descriptions[ii].EndpointUrl.StartsWith(scheme))
                        {
                            if (endpoint == null)
                            {
                                endpoint = m_descriptions[ii];
                            }

                            if (m_descriptions[ii].SecurityPolicyUri == securityPolicyUri)
                            {
                                endpoint = m_descriptions[ii];
                                break;
                            }
                        }
                    }

                    IEncodeable request = null;

                    if (String.IsNullOrEmpty(action))
                    {
                        request = BinaryDecoder.DecodeMessage(istrm, null, this.m_quotas.MessageContext);
                    }
                    else
                    {
                        string requestType = "Opc.Ua." + action + "Request";

                        request = HttpsTransportChannel.ReadSoapMessage(
                            istrm,
                            action + "Request",
                            Type.GetType(requestType),
                            this.m_quotas.MessageContext);
                    }

                    result = m_callback.BeginProcessRequest(
                        m_listenerId,
                        endpoint,
                        request as IServiceRequest,
                        null,
                        callbackData);
                }
            }
            catch (Exception e)
            {
                Utils.Trace(e, "HTTPSLISTENER - Unexpected error processing request.");
            }

            return(result);
        }
Beispiel #13
0
        /// <summary>
        /// Handles requests arriving from a channel.
        /// </summary>
        public async Task SendAsync(HttpContext context)
        {
            IAsyncResult result = null;

            try
            {
                if (m_callback == null)
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.NotImplemented;
                    await context.Response.WriteAsync(string.Empty);

                    return;
                }

                if (context.Request.ContentType != "application/octet-stream")
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.BadRequest;
                    await context.Response.WriteAsync("HTTPSLISTENER - Unsupported content type.");

                    return;
                }

                int    length = (int)context.Request.ContentLength;
                byte[] buffer = await ReadBodyAsync(context.Request);

                if (buffer.Length != length)
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.BadRequest;
                    await context.Response.WriteAsync("HTTPSLISTENER - Couldn't decode buffer.");

                    return;
                }

                IServiceRequest input = (IServiceRequest)BinaryDecoder.DecodeMessage(buffer, null, m_quotas.MessageContext);

                // extract the JWT token from the HTTP headers.
                if (input.RequestHeader == null)
                {
                    input.RequestHeader = new RequestHeader();
                }

                if (NodeId.IsNull(input.RequestHeader.AuthenticationToken) && input.TypeId != DataTypeIds.CreateSessionRequest)
                {
                    if (context.Request.Headers.Keys.Contains("Authorization"))
                    {
                        foreach (string value in context.Request.Headers["Authorization"])
                        {
                            if (value.StartsWith("Bearer"))
                            {
                                input.RequestHeader.AuthenticationToken = new NodeId(value.Substring("Bearer ".Length).Trim());
                            }
                        }
                    }
                }

                EndpointDescription endpoint = null;

                foreach (var ep in m_descriptions)
                {
                    if (ep.EndpointUrl.StartsWith(Utils.UriSchemeHttps))
                    {
                        endpoint = ep;
                        break;
                    }
                }

                IPAddress remoteIP   = (context.Connection == null ? null : context.Connection.RemoteIpAddress);
                int       remotePort = (context.Connection == null ? 0 : context.Connection.RemotePort);

                result = m_callback.BeginProcessRequest(
                    m_listenerId,
                    endpoint,
                    input as IServiceRequest,
                    null,
                    null,
                    remoteIP,      // HONEYPOT - pass the remote IP address as an additional parameter.
                    remotePort);   // HONEYPOT - pass the remote port as an additional parameter.

                IServiceResponse output = m_callback.EndProcessRequest(result);

                byte[] response = BinaryEncoder.EncodeMessage(output, m_quotas.MessageContext);
                context.Response.ContentLength = response.Length;
                context.Response.ContentType   = context.Request.ContentType;
                context.Response.StatusCode    = (int)HttpStatusCode.OK;
                await context.Response.Body.WriteAsync(response, 0, response.Length);
            }
            catch (Exception e)
            {
                Utils.Trace(e, "HTTPSLISTENER - Unexpected error processing request.");
                context.Response.ContentLength = e.Message.Length;
                context.Response.ContentType   = "text/plain";
                context.Response.StatusCode    = (int)HttpStatusCode.InternalServerError;
                await context.Response.WriteAsync(e.Message);
            }
        }
Beispiel #14
0
        /// <summary>
        /// Handles requests arriving from a channel.
        /// </summary>
        public async Task SendAsync(HttpContext context)
        {
            string            message = string.Empty;
            CancellationToken ct      = context.RequestAborted;

            try
            {
                if (m_callback == null)
                {
                    await WriteResponseAsync(context.Response, message, HttpStatusCode.NotImplemented).ConfigureAwait(false);

                    return;
                }

                if (context.Request.ContentType != kApplicationContentType)
                {
                    message = "HTTPSLISTENER - Unsupported content type.";
                    await WriteResponseAsync(context.Response, message, HttpStatusCode.BadRequest).ConfigureAwait(false);

                    return;
                }

                int    length = (int)context.Request.ContentLength;
                byte[] buffer = await ReadBodyAsync(context.Request).ConfigureAwait(false);

                if (buffer.Length != length)
                {
                    message = "HTTPSLISTENER - Invalid buffer.";
                    await WriteResponseAsync(context.Response, message, HttpStatusCode.BadRequest).ConfigureAwait(false);

                    return;
                }

                IServiceRequest input = (IServiceRequest)BinaryDecoder.DecodeMessage(buffer, null, m_quotas.MessageContext);

                // extract the JWT token from the HTTP headers.
                if (input.RequestHeader == null)
                {
                    input.RequestHeader = new RequestHeader();
                }

                if (NodeId.IsNull(input.RequestHeader.AuthenticationToken) &&
                    input.TypeId != DataTypeIds.CreateSessionRequest)
                {
                    if (context.Request.Headers.ContainsKey(kAuthorizationKey))
                    {
                        foreach (string value in context.Request.Headers[kAuthorizationKey])
                        {
                            if (value.StartsWith(kBearerKey, StringComparison.OrdinalIgnoreCase))
                            {
                                // note: use NodeId(string, uint) to avoid the NodeId.Parse call.
                                input.RequestHeader.AuthenticationToken = new NodeId(value.Substring(kBearerKey.Length + 1).Trim(), 0);
                            }
                        }
                    }
                }

                if (!context.Request.Headers.TryGetValue(Profiles.HttpsSecurityPolicyHeader, out var header))
                {
                    header = SecurityPolicies.None;
                }

                EndpointDescription endpoint = null;
                foreach (var ep in m_descriptions)
                {
                    if (ep.EndpointUrl.StartsWith(Utils.UriSchemeHttps, StringComparison.Ordinal))
                    {
                        if (!string.IsNullOrEmpty(header))
                        {
                            if (!string.Equals(ep.SecurityPolicyUri, header, StringComparison.Ordinal))
                            {
                                continue;
                            }
                        }

                        endpoint = ep;
                        break;
                    }
                }

                if (endpoint == null &&
                    input.TypeId != DataTypeIds.GetEndpointsRequest &&
                    input.TypeId != DataTypeIds.FindServersRequest)
                {
                    message = "Connection refused, invalid security policy.";
                    Utils.LogError(message);
                    await WriteResponseAsync(context.Response, message, HttpStatusCode.Unauthorized).ConfigureAwait(false);

                    return;
                }

                // note: do not use Task.Factory.FromAsync here
                var result = m_callback.BeginProcessRequest(
                    m_listenerId,
                    endpoint,
                    input as IServiceRequest,
                    null,
                    null);

                IServiceResponse output = m_callback.EndProcessRequest(result);

                byte[] response = BinaryEncoder.EncodeMessage(output, m_quotas.MessageContext);
                context.Response.ContentLength = response.Length;
                context.Response.ContentType   = context.Request.ContentType;
                context.Response.StatusCode    = (int)HttpStatusCode.OK;
#if NETSTANDARD2_1 || NET5_0_OR_GREATER || NETCOREAPP3_1_OR_GREATER
                await context.Response.Body.WriteAsync(response.AsMemory(0, response.Length), ct).ConfigureAwait(false);
#else
                await context.Response.Body.WriteAsync(response, 0, response.Length, ct).ConfigureAwait(false);
#endif
                return;
            }
            catch (Exception e)
            {
                message = "HTTPSLISTENER - Unexpected error processing request.";
                Utils.LogError(e, message);
            }

            await WriteResponseAsync(context.Response, message, HttpStatusCode.InternalServerError).ConfigureAwait(false);
        }
        /// <summary>
        /// Processes a request message.
        /// </summary>
        private bool ProcessRequestMessage(uint messageType, ArraySegment <byte> messageChunk)
        {
            // validate the channel state.
            if (State != TcpChannelState.Open)
            {
                ForceChannelFault(StatusCodes.BadTcpMessageTypeInvalid, "Client sent an unexpected request message.");
                return(false);
            }

            // validate security on the message.
            ChannelToken token          = null;
            uint         requestId      = 0;
            uint         sequenceNumber = 0;

            ArraySegment <byte> messageBody;

            try
            {
                messageBody = ReadSymmetricMessage(messageChunk, true, out token, out requestId, out sequenceNumber);

                // check for replay attacks.
                if (!VerifySequenceNumber(sequenceNumber, "ProcessRequestMessage"))
                {
                    throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid);
                }

                if (token == CurrentToken && PreviousToken != null && !PreviousToken.Expired)
                {
                    Utils.Trace("Server Revoked Token. ChannelId={1}, TokenId={0}", PreviousToken.TokenId, PreviousToken.ChannelId, DateTime.UtcNow);
                    PreviousToken.Lifetime = 0;
                }
            }
            catch (Exception e)
            {
                Utils.Trace("Could not verify security on incoming request.");
                ForceChannelFault(e, StatusCodes.BadSecurityChecksFailed, "Could not verify security on incoming request.");
                return(false);
            }

            BufferCollection chunksToProcess = null;

            try
            {
                // check for an abort.
                if (TcpMessageType.IsAbort(messageType))
                {
                    Utils.Trace("Request was aborted.");
                    chunksToProcess = GetSavedChunks(requestId, messageBody);
                    return(true);
                }

                // check if it is necessary to wait for more chunks.
                if (!TcpMessageType.IsFinal(messageType))
                {
                    SaveIntermediateChunk(requestId, messageBody);
                    return(true);
                }

                Utils.Trace("Channel {0}: ProcessRequestMessage {1}", ChannelId, requestId);

                // get the chunks to process.
                chunksToProcess = GetSavedChunks(requestId, messageBody);

                // decode the request.
                IServiceRequest request = BinaryDecoder.DecodeMessage(new ArraySegmentStream(chunksToProcess), null, Quotas.MessageContext) as IServiceRequest;

                if (request == null)
                {
                    SendServiceFault(token, requestId, ServiceResult.Create(StatusCodes.BadStructureMissing, "Could not parse request body."));
                    return(true);
                }

                // ensure that only discovery requests come through unsecured.
                if (DiscoveryOnly)
                {
                    if (!(request is GetEndpointsRequest || request is FindServersRequest))
                    {
                        SendServiceFault(token, requestId, ServiceResult.Create(StatusCodes.BadSecurityPolicyRejected, "Channel can only be used for discovery."));
                        return(true);
                    }
                }

                // hand the request to the server.
                RequestReceived?.Invoke(this, requestId, request);

                return(true);
            }
            catch (Exception e)
            {
                Utils.Trace(e, "Unexpected error processing request.");
                SendServiceFault(token, requestId, ServiceResult.Create(e, StatusCodes.BadTcpInternalError, "Unexpected error processing request."));
                return(true);
            }
            finally
            {
                if (chunksToProcess != null)
                {
                    chunksToProcess.Release(BufferManager, "ProcessRequestMessage");
                }
            }
        }
        /// <summary>
        /// Processes an CloseSecureChannel request message.
        /// </summary>
        private bool ProcessCloseSecureChannelRequest(uint messageType, ArraySegment <byte> messageChunk)
        {
            // validate security on the message.
            ChannelToken token          = null;
            uint         requestId      = 0;
            uint         sequenceNumber = 0;

            ArraySegment <byte> messageBody;

            try
            {
                messageBody = ReadSymmetricMessage(messageChunk, true, out token, out requestId, out sequenceNumber);

                // check for replay attacks.
                if (!VerifySequenceNumber(sequenceNumber, "ProcessCloseSecureChannelRequest"))
                {
                    throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid);
                }
            }
            catch (Exception e)
            {
                throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, e, "Could not verify security on CloseSecureChannel request.");
            }

            BufferCollection chunksToProcess = null;

            try
            {
                // check if it is necessary to wait for more chunks.
                if (!TcpMessageType.IsFinal(messageType))
                {
                    SaveIntermediateChunk(requestId, messageBody);
                    return(false);
                }

                // get the chunks to process.
                chunksToProcess = GetSavedChunks(requestId, messageBody);

                CloseSecureChannelRequest request = BinaryDecoder.DecodeMessage(
                    new ArraySegmentStream(chunksToProcess),
                    typeof(CloseSecureChannelRequest),
                    Quotas.MessageContext) as CloseSecureChannelRequest;

                if (request == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadStructureMissing, "Could not parse CloseSecureChannel request body.");
                }

                // send the response.
                // SendCloseSecureChannelResponse(requestId, token, request);
            }
            catch (Exception e)
            {
                Utils.Trace(e, "Unexpected error processing OpenSecureChannel request.");
            }
            finally
            {
                if (chunksToProcess != null)
                {
                    chunksToProcess.Release(BufferManager, "ProcessCloseSecureChannelRequest");
                }

                Utils.Trace(
                    "{0} ProcessCloseSecureChannelRequest Socket={0:X8}, ChannelId={1}, TokenId={2}",
                    ChannelName,
                    (Socket != null) ? Socket.Handle : 0,
                    (CurrentToken != null) ? CurrentToken.ChannelId : 0,
                    (CurrentToken != null) ? CurrentToken.TokenId : 0);

                // close the channel.
                ChannelClosed();
            }

            // return false would double free the buffer
            return(true);
        }
        /// <summary>
        /// Processes an OpenSecureChannel request message.
        /// </summary>
        private bool ProcessOpenSecureChannelRequest(uint messageType, ArraySegment <byte> messageChunk)
        {
            // validate the channel state.
            if (State != TcpChannelState.Opening && State != TcpChannelState.Open)
            {
                ForceChannelFault(StatusCodes.BadTcpMessageTypeInvalid, "Client sent an unexpected OpenSecureChannel message.");
                return(false);
            }

            // parse the security header.
            uint             channelId         = 0;
            X509Certificate2 clientCertificate = null;
            uint             requestId         = 0;
            uint             sequenceNumber    = 0;

            ArraySegment <byte> messageBody;

            try
            {
                messageBody = ReadAsymmetricMessage(
                    messageChunk,
                    ServerCertificate,
                    out channelId,
                    out clientCertificate,
                    out requestId,
                    out sequenceNumber);

                // check for replay attacks.
                if (!VerifySequenceNumber(sequenceNumber, "ProcessOpenSecureChannelRequest"))
                {
                    throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid);
                }
            }
            catch (Exception e)
            {
                ServiceResultException innerException = e.InnerException as ServiceResultException;

                // If the certificate structre, signature and trust list checks pass, we return the other specific validation errors instead of BadSecurityChecksFailed
                if (innerException != null)
                {
                    if (innerException.StatusCode == StatusCodes.BadCertificateUntrusted ||
                        innerException.StatusCode == StatusCodes.BadCertificateChainIncomplete ||
                        innerException.StatusCode == StatusCodes.BadCertificateRevoked ||
                        innerException.StatusCode == StatusCodes.BadCertificateInvalid ||
                        (innerException.InnerResult != null && innerException.InnerResult.StatusCode == StatusCodes.BadCertificateUntrusted))
                    {
                        ForceChannelFault(StatusCodes.BadSecurityChecksFailed, e.Message);
                        return(false);
                    }
                    else if (innerException.StatusCode == StatusCodes.BadCertificateTimeInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerTimeInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateHostNameInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateUriInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateUseNotAllowed ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerUseNotAllowed ||
                             innerException.StatusCode == StatusCodes.BadCertificateRevocationUnknown ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerRevocationUnknown ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerRevoked)
                    {
                        ForceChannelFault(innerException, innerException.StatusCode, e.Message);
                        return(false);
                    }
                }

                ForceChannelFault(e, StatusCodes.BadSecurityChecksFailed, "Could not verify security on OpenSecureChannel request.");
                return(false);
            }

            BufferCollection chunksToProcess = null;

            try
            {
                bool firstCall = ClientCertificate == null;

                // must ensure the same certificate was used.
                if (ClientCertificate != null)
                {
                    CompareCertificates(ClientCertificate, clientCertificate, false);
                }
                else
                {
                    ClientCertificate = clientCertificate;
                }

                // check if it is necessary to wait for more chunks.
                if (!TcpMessageType.IsFinal(messageType))
                {
                    SaveIntermediateChunk(requestId, messageBody);
                    return(false);
                }

                // create a new token.
                ChannelToken token = CreateToken();

                token.TokenId     = GetNewTokenId();
                token.ServerNonce = CreateNonce();

                // get the chunks to process.
                chunksToProcess = GetSavedChunks(requestId, messageBody);

                OpenSecureChannelRequest request = (OpenSecureChannelRequest)BinaryDecoder.DecodeMessage(
                    new ArraySegmentStream(chunksToProcess),
                    typeof(OpenSecureChannelRequest),
                    Quotas.MessageContext);

                if (request == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadStructureMissing, "Could not parse OpenSecureChannel request body.");
                }

                // check the security mode.
                if (request.SecurityMode != SecurityMode)
                {
                    ReviseSecurityMode(firstCall, request.SecurityMode);
                }

                // check the client nonce.
                token.ClientNonce = request.ClientNonce;

                if (!ValidateNonce(token.ClientNonce))
                {
                    throw ServiceResultException.Create(StatusCodes.BadNonceInvalid, "Client nonce is not the correct length or not random enough.");
                }

                // choose the lifetime.
                int lifetime = (int)request.RequestedLifetime;

                if (lifetime < TcpMessageLimits.MinSecurityTokenLifeTime)
                {
                    lifetime = TcpMessageLimits.MinSecurityTokenLifeTime;
                }

                if (lifetime > 0 && lifetime < token.Lifetime)
                {
                    token.Lifetime = lifetime;
                }

                // check the request type.
                SecurityTokenRequestType requestType = request.RequestType;

                if (requestType == SecurityTokenRequestType.Issue && State != TcpChannelState.Opening)
                {
                    throw ServiceResultException.Create(StatusCodes.BadRequestTypeInvalid, "Cannot request a new token for an open channel.");
                }

                if (requestType == SecurityTokenRequestType.Renew && State != TcpChannelState.Open)
                {
                    // may be reconnecting to a dropped channel.
                    if (State == TcpChannelState.Opening)
                    {
                        // tell the listener to find the channel that can process the request.
                        Listener.ReconnectToExistingChannel(
                            Socket,
                            requestId,
                            sequenceNumber,
                            channelId,
                            ClientCertificate,
                            token,
                            request);

                        Utils.Trace(
                            "{0} ReconnectToExistingChannel Socket={0:X8}, ChannelId={1}, TokenId={2}",
                            ChannelName,
                            (Socket != null) ? Socket.Handle : 0,
                            (CurrentToken != null) ? CurrentToken.ChannelId : 0,
                            (CurrentToken != null) ? CurrentToken.TokenId : 0);

                        // close the channel.
                        ChannelClosed();

                        // nothing more to do.
                        return(false);
                    }

                    throw ServiceResultException.Create(StatusCodes.BadRequestTypeInvalid, "Cannot request to renew a token for a channel that has not been opened.");
                }

                // check the channel id.
                if (requestType == SecurityTokenRequestType.Renew && channelId != ChannelId)
                {
                    throw ServiceResultException.Create(StatusCodes.BadTcpSecureChannelUnknown, "Do not recognize the secure channel id provided.");
                }

                // log security information.
                if (requestType == SecurityTokenRequestType.Issue)
                {
                    Opc.Ua.Security.Audit.SecureChannelCreated(
                        m_ImplementationString,
                        Listener.EndpointUrl.ToString(),
                        Utils.Format("{0}", ChannelId),
                        EndpointDescription,
                        ClientCertificate,
                        ServerCertificate,
                        BinaryEncodingSupport.Required);
                }
                else
                {
                    Opc.Ua.Security.Audit.SecureChannelRenewed(
                        m_ImplementationString,
                        Utils.Format("{0}", ChannelId));
                }

                if (requestType == SecurityTokenRequestType.Renew)
                {
                    SetRenewedToken(token);
                }
                else
                {
                    ActivateToken(token);
                }

                State = TcpChannelState.Open;

                // send the response.
                SendOpenSecureChannelResponse(requestId, token, request);

                // notify reverse
                CompleteReverseHello(null);

                // notify any monitors.
                NotifyMonitors(ServiceResult.Good, false);

                return(false);
            }
            catch (Exception e)
            {
                SendServiceFault(requestId, ServiceResult.Create(e, StatusCodes.BadTcpInternalError, "Unexpected error processing OpenSecureChannel request."));
                CompleteReverseHello(e);
                return(false);
            }
            finally
            {
                if (chunksToProcess != null)
                {
                    chunksToProcess.Release(BufferManager, "ProcessOpenSecureChannelRequest");
                }
            }
        }
Beispiel #18
0
        /// <summary>
        /// Handles requests arriving from a channel.
        /// </summary>
        public async Task SendAsync(HttpContext context)
        {
            IAsyncResult result = null;

            try
            {
                if (m_callback == null)
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.NotImplemented;
                    await context.Response.WriteAsync(string.Empty).ConfigureAwait(false);

                    return;
                }

                if (context.Request.ContentType != "application/octet-stream")
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.BadRequest;
                    await context.Response.WriteAsync("HTTPSLISTENER - Unsupported content type.").ConfigureAwait(false);

                    return;
                }

                int    length = (int)context.Request.ContentLength;
                byte[] buffer = await ReadBodyAsync(context.Request).ConfigureAwait(false);

                if (buffer.Length != length)
                {
                    context.Response.ContentLength = 0;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.BadRequest;
                    await context.Response.WriteAsync("HTTPSLISTENER - Couldn't decode buffer.").ConfigureAwait(false);

                    return;
                }

                IServiceRequest input = (IServiceRequest)BinaryDecoder.DecodeMessage(buffer, null, m_quotas.MessageContext);

                // extract the JWT token from the HTTP headers.
                if (input.RequestHeader == null)
                {
                    input.RequestHeader = new RequestHeader();
                }

                if (NodeId.IsNull(input.RequestHeader.AuthenticationToken) && input.TypeId != DataTypeIds.CreateSessionRequest)
                {
                    if (context.Request.Headers.ContainsKey("Authorization"))
                    {
                        foreach (string value in context.Request.Headers["Authorization"])
                        {
                            if (value.StartsWith("Bearer", StringComparison.OrdinalIgnoreCase))
                            {
                                // note: use NodeId(string, uint) to avoid the NodeId.Parse call.
                                input.RequestHeader.AuthenticationToken = new NodeId(value.Substring("Bearer ".Length).Trim(), 0);
                            }
                        }
                    }
                }

                if (!context.Request.Headers.TryGetValue("OPCUA-SecurityPolicy", out var header))
                {
                    header = SecurityPolicies.None;
                }

                EndpointDescription endpoint = null;
                foreach (var ep in m_descriptions)
                {
                    if (ep.EndpointUrl.StartsWith(Utils.UriSchemeHttps, StringComparison.Ordinal))
                    {
                        if (!string.IsNullOrEmpty(header))
                        {
                            if (!string.Equals(ep.SecurityPolicyUri, header, StringComparison.Ordinal))
                            {
                                continue;
                            }
                        }

                        endpoint = ep;
                        break;
                    }
                }

                if (endpoint == null &&
                    input.TypeId != DataTypeIds.GetEndpointsRequest &&
                    input.TypeId != DataTypeIds.FindServersRequest)
                {
                    var message = "Connection refused, invalid security policy.";
                    Utils.LogError(message);
                    context.Response.ContentLength = message.Length;
                    context.Response.ContentType   = "text/plain";
                    context.Response.StatusCode    = (int)HttpStatusCode.Unauthorized;
                    await context.Response.WriteAsync(message).ConfigureAwait(false);
                }

                result = m_callback.BeginProcessRequest(
                    m_listenerId,
                    endpoint,
                    input as IServiceRequest,
                    null,
                    null);

                IServiceResponse output = m_callback.EndProcessRequest(result);

                byte[] response = BinaryEncoder.EncodeMessage(output, m_quotas.MessageContext);
                context.Response.ContentLength = response.Length;
                context.Response.ContentType   = context.Request.ContentType;
                context.Response.StatusCode    = (int)HttpStatusCode.OK;
#if NETSTANDARD2_1 || NET5_0_OR_GREATER || NETCOREAPP3_1_OR_GREATER
                await context.Response.Body.WriteAsync(response.AsMemory(0, response.Length)).ConfigureAwait(false);
#else
                await context.Response.Body.WriteAsync(response, 0, response.Length).ConfigureAwait(false);
#endif
            }
            catch (Exception e)
            {
                Utils.LogError(e, "HTTPSLISTENER - Unexpected error processing request.");
                context.Response.ContentLength = e.Message.Length;
                context.Response.ContentType   = "text/plain";
                context.Response.StatusCode    = (int)HttpStatusCode.InternalServerError;
                await context.Response.WriteAsync(e.Message).ConfigureAwait(false);
            }
        }
Beispiel #19
0
        /// <summary cref="IClientMessageInspector.AfterReceiveReply" />
        public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            // check for fault.
            if (reply.IsFault)
            {
                return;
            }

            // parse request parameters.
            object[] parameters = correlationState as object[];

            if (parameters == null || parameters.Length != 3)
            {
                throw new InvalidOperationException("Cannot decode request because the IClientMessageInspector not configured properly.");
            }

            // extract request parameters.
            MessageVersion  messageVersion = parameters[0] as MessageVersion;
            string          action         = parameters[1] as string;
            IServiceMessage request        = parameters[2] as IServiceMessage;

            object encodeable = null;

            if (!reply.Properties.TryGetValue(MessageProperties.UnencodedBody, out encodeable))
            {
                // extract binary encoded response from body.
                XmlDictionaryReader reader = reply.GetReaderAtBodyContents();
                reader.MoveToStartElement("InvokeServiceResponse", Namespaces.OpcUaXsd);
                byte[] response = reader.ReadElementContentAsBase64();

                // decode body.
                try
                {
                    encodeable = BinaryDecoder.DecodeMessage(response, null, m_messageContext);
                }
                catch (Exception e)
                {
                    ServiceResult error = ServiceResult.Create(
                        e,
                        StatusCodes.BadDecodingError,
                        "Could not decoding incoming response message.");

                    ServiceFault fault = new ServiceFault();

                    fault.ResponseHeader.RequestHandle = request.GetRequest().RequestHeader.RequestHandle;
                    fault.ResponseHeader.Timestamp     = DateTime.UtcNow;
                    fault.ResponseHeader.ServiceResult = error.Code;

                    StringTable stringTable = new StringTable();

                    fault.ResponseHeader.ServiceDiagnostics = new DiagnosticInfo(
                        error,
                        DiagnosticsMasks.NoInnerStatus,
                        true,
                        stringTable);

                    fault.ResponseHeader.StringTable = stringTable.ToArray();

                    encodeable = fault;
                }
            }

            object unencodedBody = request.CreateResponse((IServiceResponse)encodeable);

            // create the unencoded reply message.
            Message unencodedReply = Message.CreateMessage(
                messageVersion,
                action + "Response",
                unencodedBody);

            unencodedReply.Headers.MessageId = reply.Headers.MessageId;
            unencodedReply.Headers.RelatesTo = reply.Headers.RelatesTo;

            unencodedReply.Properties.Add(MessageProperties.UnencodedBody, unencodedBody);

            // replace the incoming message.
            reply = unencodedReply;
        }