/// <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); }
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); }
/// <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)); }
/// <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); }
/// <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())); }
/// <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; } }
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)); } } }
// ***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); } }
/// <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); }
/// <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); } }
/// <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"); } } }
/// <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); } }
/// <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; }