public static LogEntry For(CloseSecureChannelRequest request) { LogEntry entry = new LogEntry("CloseSecureChannelRequest"); entry.Add("RequestHeader", For(request.RequestHeader)); return(entry); }
/// <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); } }
/// <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); }
/// <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); }
/// <summary> /// Initializes the message with the body. /// </summary> public CloseSecureChannelMessage(CloseSecureChannelRequest CloseSecureChannelRequest) { this.CloseSecureChannelRequest = CloseSecureChannelRequest; }