Example #1
0
        public static LogEntry For(CloseSecureChannelRequest request)
        {
            LogEntry entry = new LogEntry("CloseSecureChannelRequest");

            entry.Add("RequestHeader", For(request.RequestHeader));
            return(entry);
        }
Example #2
0
        /// <summary>
        /// Send close secure channel request on transport channel.
        /// </summary>
        /// <param name="request">A service request</param>
        /// <param name="token">A cancellation token</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        private async Task SendCloseSecureChannelRequestAsync(CloseSecureChannelRequest request, CancellationToken token)
        {
            var bodyStream = _streamManager.GetStream("SendCloseSecureChannelRequestAsync");

            using (var bodyEncoder = StackProfile.EncodingProvider.CreateEncoder(bodyStream, this, keepStreamOpen: false))
            {
                bodyEncoder.WriteRequest(request);
                bodyStream.Position = 0;

                var   handle = request.RequestHeader !.RequestHandle;
                await _conversation !.EncryptMessageAsync(bodyStream, MessageTypes.CLOF, handle, SendAsync, token);
            }
        }
Example #3
0
        /// <inheritdoc/>
        /// <seealso href="https://reference.opcfoundation.org/v104/Core/docs/Part4/5.5.3/">OPC UA specification Part 4: Services, 5.5.3</seealso>
        protected override async Task OnCloseAsync(CancellationToken token = default)
        {
            try
            {
                var request = new CloseSecureChannelRequest {
                    RequestHeader = new RequestHeader {
                        TimeoutHint = TimeoutHint, ReturnDiagnostics = DiagnosticsHint
                    }
                };
                await RequestAsync(request).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                _logger?.LogError($"Error closing secure channel. {ex.Message}");
            }

            await base.OnCloseAsync(token).ConfigureAwait(false);
        }
        /// <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);
        }
Example #5
0
        /// <summary>
        /// Sends an CloseSecureChannel request message.
        /// </summary>
        private void SendCloseSecureChannelRequest(WriteOperation operation)
        {
            // Utils.Trace("Channel {0}: SendCloseSecureChannelRequest()", ChannelId);

            // supress reconnects if an error occurs.
            m_waitBetweenReconnects = Timeout.Infinite;

            // check for valid token.
            TcpChannelToken currentToken = CurrentToken;

            if (currentToken == null)
            {
                throw new ServiceResultException(StatusCodes.BadSecureChannelClosed);
            }

            CloseSecureChannelRequest request = new CloseSecureChannelRequest();
            request.RequestHeader.Timestamp = DateTime.UtcNow;
            
            // limits should never be exceeded sending a close message.
            bool limitsExceeded = false;

            // construct the message.
            BufferCollection buffers = WriteSymmetricMessage(
                TcpMessageType.Close,
                operation.RequestId,
                currentToken,
                request,
                true,
                out limitsExceeded);
            
            // send the message.
            try
            {
                BeginWriteMessage(buffers, 1000, operation);
                buffers = null;
            }
            finally
            {
                if (buffers != null)
                {
                    buffers.Release(BufferManager, "SendCloseSecureChannelRequest");
                }
            }
        }
        private async Task SendCloseSecureChannelRequestAsync(CloseSecureChannelRequest request, CancellationToken token)
        {
            var bodyStream = SerializableBytes.CreateWritableStream();
            var bodyEncoder = new BinaryEncoder(bodyStream, this);
            try
            {
                bodyEncoder.WriteNodeId(null, CloseSecureChannelRequestNodeId);
                request.Encode(bodyEncoder);
                bodyStream.Position = 0;
                if (bodyStream.Length > this.RemoteMaxMessageSize)
                {
                    throw new ServiceResultException(StatusCodes.BadEncodingLimitsExceeded);
                }

                // write chunks
                int chunkCount = 0;
                int bodyCount = (int)(bodyStream.Length - bodyStream.Position);
                while (bodyCount > 0)
                {
                    chunkCount++;
                    if (this.RemoteMaxChunkCount > 0 && chunkCount > this.RemoteMaxChunkCount)
                    {
                        throw new ServiceResultException(StatusCodes.BadEncodingLimitsExceeded);
                    }

                    var stream = new MemoryStream(this.sendBuffer, 0, (int)this.RemoteReceiveBufferSize, true, true);
                    var encoder = new BinaryEncoder(stream, this);
                    try
                    {
                        // header
                        encoder.WriteUInt32(null, UaTcpMessageTypes.CLOF);
                        encoder.WriteUInt32(null, 0u);
                        encoder.WriteUInt32(null, this.ChannelId);

                        // symmetric security header
                        encoder.WriteUInt32(null, this.TokenId);

                        // detect new TokenId
                        if (this.TokenId != this.currentClientTokenId)
                        {
                            this.currentClientTokenId = this.TokenId;

                            // update signer and encrypter with new symmetric keys
                            if (this.symIsSigned)
                            {
                                this.symSigner.Key = this.clientSigningKey;
                                if (this.symIsEncrypted)
                                {
                                    this.currentClientEncryptingKey = this.clientEncryptingKey;
                                    this.currentClientInitializationVector = this.clientInitializationVector;
                                    this.symEncryptor = this.symEncryptionAlgorithm.CreateEncryptor(this.currentClientEncryptingKey, this.currentClientInitializationVector);
                                }
                            }
                        }

                        int plainHeaderSize = encoder.Position;

                        // sequence header
                        encoder.WriteUInt32(null, this.GetNextSequenceNumber());
                        encoder.WriteUInt32(null, request.RequestHeader.RequestHandle);

                        // body
                        int paddingHeaderSize;
                        int maxBodySize;
                        int bodySize;
                        int paddingSize;
                        int chunkSize;
                        if (this.symIsEncrypted)
                        {
                            paddingHeaderSize = this.symEncryptionBlockSize > 256 ? 2 : 1;
                            maxBodySize = ((((int)this.RemoteReceiveBufferSize - plainHeaderSize - this.symSignatureSize - paddingHeaderSize) / this.symEncryptionBlockSize) * this.symEncryptionBlockSize) - SequenceHeaderSize;
                            if (bodyCount < maxBodySize)
                            {
                                bodySize = bodyCount;
                                paddingSize = (this.symEncryptionBlockSize - ((SequenceHeaderSize + bodySize + paddingHeaderSize + this.symSignatureSize) % this.symEncryptionBlockSize)) % this.symEncryptionBlockSize;
                            }
                            else
                            {
                                bodySize = maxBodySize;
                                paddingSize = 0;
                            }

                            chunkSize = plainHeaderSize + (((SequenceHeaderSize + bodySize + paddingSize + paddingHeaderSize + this.symSignatureSize) / this.symEncryptionBlockSize) * this.symEncryptionBlockSize);
                        }
                        else
                        {
                            paddingHeaderSize = 0;
                            paddingSize = 0;
                            maxBodySize = (int)this.RemoteReceiveBufferSize - plainHeaderSize - this.symSignatureSize - SequenceHeaderSize;
                            if (bodyCount < maxBodySize)
                            {
                                bodySize = bodyCount;
                            }
                            else
                            {
                                bodySize = maxBodySize;
                            }

                            chunkSize = plainHeaderSize + SequenceHeaderSize + bodySize + this.symSignatureSize;
                        }

                        bodyStream.Read(this.sendBuffer, encoder.Position, bodySize);
                        encoder.Position += bodySize;
                        bodyCount -= bodySize;

                        // padding
                        if (this.symIsEncrypted)
                        {
                            var paddingByte = (byte)(paddingSize & 0xFF);
                            encoder.WriteByte(null, paddingByte);
                            for (int i = 0; i < paddingSize; i++)
                            {
                                encoder.WriteByte(null, paddingByte);
                            }

                            if (paddingHeaderSize == 2)
                            {
                                var extraPaddingByte = (byte)((paddingSize >> 8) & 0xFF);
                                encoder.WriteByte(null, extraPaddingByte);
                            }
                        }

                        // update message type and (encrypted) length
                        var position = encoder.Position;
                        encoder.Position = 3;
                        encoder.WriteByte(null, bodyCount > 0 ? (byte)'C' : (byte)'F');
                        encoder.WriteUInt32(null, (uint)chunkSize);
                        encoder.Position = position;

                        // signature
                        if (this.symIsSigned)
                        {
                            byte[] signature = this.symSigner.ComputeHash(this.sendBuffer, 0, position);
                            if (signature != null)
                            {
                                encoder.Write(signature, 0, signature.Length);
                            }
                        }

                        // encrypt
                        position = encoder.Position;
                        if (this.symIsEncrypted)
                        {
                            using (var symEncryptor = this.symEncryptionAlgorithm.CreateEncryptor(this.currentClientEncryptingKey, this.currentClientInitializationVector))
                            {
                                int inputCount = position - plainHeaderSize;
                                Debug.Assert(inputCount % symEncryptor.InputBlockSize == 0, "Input data is not an even number of encryption blocks.");
                                symEncryptor.TransformBlock(this.sendBuffer, plainHeaderSize, inputCount, this.sendBuffer, plainHeaderSize);
                                symEncryptor.TransformFinalBlock(this.sendBuffer, position, 0);
                            }
                        }

                        // pass buffer to transport
                        await this.SendAsync(this.sendBuffer, 0, position, token).ConfigureAwait(false);
                    }
                    finally
                    {
                        encoder.Dispose();
                    }
                }
            }
            finally
            {
                bodyEncoder.Dispose();
            }
        }
        protected override async Task OnCloseAsync(CancellationToken token)
        {
            token.ThrowIfCancellationRequested();
            var closeSecureChannelRequest = new CloseSecureChannelRequest();
            await this.RequestAsync(closeSecureChannelRequest).ConfigureAwait(false);

            try
            {
                await Task.WhenAll(this.sendRequestsTask, this.receiveResponsesTask).WithCancellation(token).ConfigureAwait(false);
            }
            catch (TimeoutException)
            {
            }

            this.channelCts.Cancel();
            await base.OnCloseAsync(token).ConfigureAwait(false);
        }
Example #8
0
 /// <summary>
 /// Initializes the message with the body.
 /// </summary>
 public CloseSecureChannelMessage(CloseSecureChannelRequest CloseSecureChannelRequest)
 {
     this.CloseSecureChannelRequest = CloseSecureChannelRequest;
 }