/// <summary> /// Compare encoded/decoded dataset messages /// </summary> /// <param name="uadpDataSetMessage"></param> /// <returns></returns> private void CompareEncodeDecode(UadpDataSetMessage uadpDataSetMessage) { IServiceMessageContext messageContextEncode = new ServiceMessageContext(); byte[] bytes; var memoryStream = new MemoryStream(); using (BinaryEncoder encoder = new BinaryEncoder(memoryStream, messageContextEncode, true)) { uadpDataSetMessage.Encode(encoder); _ = encoder.Close(); bytes = ReadBytes(memoryStream); } UadpDataSetMessage uaDataSetMessageDecoded = new UadpDataSetMessage(); BinaryDecoder decoder = new BinaryDecoder(bytes, messageContextEncode); // workaround uaDataSetMessageDecoded.DataSetWriterId = TestDataSetWriterId; uaDataSetMessageDecoded.DecodePossibleDataSetReader(decoder, m_firstDataSetReaderType); decoder.Dispose(); // compare uadpDataSetMessage with uaDataSetMessageDecoded CompareUadpDataSetMessages(uadpDataSetMessage, uaDataSetMessageDecoded); }
public void ValidateMajorVersionEqMinorVersionEq( [Values(DataSetFieldContentMask.None, DataSetFieldContentMask.RawData, // list here all possible DataSetFieldContentMask DataSetFieldContentMask.ServerPicoSeconds, DataSetFieldContentMask.ServerTimestamp, DataSetFieldContentMask.SourcePicoSeconds, DataSetFieldContentMask.SourceTimestamp, DataSetFieldContentMask.StatusCode, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.ServerTimestamp, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.SourcePicoSeconds, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.SourceTimestamp, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.StatusCode, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.ServerTimestamp | DataSetFieldContentMask.SourcePicoSeconds, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.ServerTimestamp | DataSetFieldContentMask.SourceTimestamp, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.ServerTimestamp | DataSetFieldContentMask.StatusCode, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.ServerTimestamp | DataSetFieldContentMask.SourcePicoSeconds | DataSetFieldContentMask.SourceTimestamp, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.ServerTimestamp | DataSetFieldContentMask.SourcePicoSeconds | DataSetFieldContentMask.StatusCode, DataSetFieldContentMask.ServerPicoSeconds | DataSetFieldContentMask.ServerTimestamp | DataSetFieldContentMask.SourcePicoSeconds | DataSetFieldContentMask.SourceTimestamp | DataSetFieldContentMask.StatusCode )] DataSetFieldContentMask dataSetFieldContentMask) { const int VersionValue = 2; // Arrange UadpDataSetMessage uadpDataSetMessage = GetFirstDataSetMessage(dataSetFieldContentMask); // Act uadpDataSetMessage.SetMessageContentMask(UadpDataSetMessageContentMask.MajorVersion | UadpDataSetMessageContentMask.MinorVersion); uadpDataSetMessage.MetaDataVersion.MajorVersion = VersionValue; uadpDataSetMessage.MetaDataVersion.MinorVersion = VersionValue * 10; IServiceMessageContext messageContextEncode = new ServiceMessageContext(); byte[] bytes; var memoryStream = new MemoryStream(); using (BinaryEncoder encoder = new BinaryEncoder(memoryStream, messageContextEncode, true)) { uadpDataSetMessage.Encode(encoder); _ = encoder.Close(); bytes = ReadBytes(memoryStream); } UadpDataSetMessage uaDataSetMessageDecoded = new UadpDataSetMessage(); BinaryDecoder decoder = new BinaryDecoder(bytes, messageContextEncode); // Make sure the reader MajorVersion and MinorVersion are the same with the ones on the dataset message DataSetReaderDataType reader = (DataSetReaderDataType)m_firstDataSetReaderType.MemberwiseClone(); reader.DataSetMetaData.ConfigurationVersion.MajorVersion = VersionValue; reader.DataSetMetaData.ConfigurationVersion.MinorVersion = VersionValue * 10; // workaround uaDataSetMessageDecoded.DataSetWriterId = TestDataSetWriterId; uaDataSetMessageDecoded.DecodePossibleDataSetReader(decoder, reader); decoder.Dispose(); // Assert Assert.AreEqual(DataSetDecodeErrorReason.NoError, uaDataSetMessageDecoded.DecodeErrorReason); Assert.AreEqual(false, uaDataSetMessageDecoded.IsMetadataMajorVersionChange); Assert.AreNotEqual(null, uaDataSetMessageDecoded.DataSet); // compare uadpDataSetMessage with uaDataSetMessageDecoded CompareUadpDataSetMessages(uadpDataSetMessage, uaDataSetMessageDecoded); }
/// <summary> /// Compare encoded/decoded dataset messages /// </summary> /// <param name="uadpDataSetMessage"></param> /// <returns></returns> private void CompareEncodeDecode(UadpDataSetMessage uadpDataSetMessage) { ServiceMessageContext messageContextEncode = new ServiceMessageContext(); BinaryEncoder encoder = new BinaryEncoder(messageContextEncode); uadpDataSetMessage.Encode(encoder); byte[] bytes = ReadBytes(encoder.BaseStream); encoder.Dispose(); UadpDataSetMessage uaDataSetMessageDecoded = new UadpDataSetMessage(); BinaryDecoder decoder = new BinaryDecoder(bytes, messageContextEncode); // workaround uaDataSetMessageDecoded.DataSetWriterId = TestDataSetWriterId; uaDataSetMessageDecoded.DecodePossibleDataSetReader(decoder, m_firstDataSetReaderType); decoder.Dispose(); // compare uadpDataSetMessage with uaDataSetMessageDecoded CompareUadpDataSetMessages(uadpDataSetMessage, uaDataSetMessageDecoded); }
private async Task<IServiceResponse> ReceiveResponseAsync(CancellationToken token = default(CancellationToken)) { await this.receivingSemaphore.WaitAsync(token).ConfigureAwait(false); try { token.ThrowIfCancellationRequested(); this.ThrowIfClosedOrNotOpening(); uint sequenceNumber; uint requestId; int paddingHeaderSize; int plainHeaderSize; int bodySize; int paddingSize; var bodyStream = SerializableBytes.CreateWritableStream(); var bodyDecoder = new BinaryDecoder(bodyStream, this); try { // read chunks int chunkCount = 0; bool isFinal = false; do { chunkCount++; if (this.LocalMaxChunkCount > 0 && chunkCount > this.LocalMaxChunkCount) { throw new ServiceResultException(StatusCodes.BadEncodingLimitsExceeded); } var count = await this.ReceiveAsync(this.receiveBuffer, 0, (int)this.LocalReceiveBufferSize, token).ConfigureAwait(false); if (count == 0) { return null; } var stream = new MemoryStream(this.receiveBuffer, 0, count, true, true); var decoder = new BinaryDecoder(stream, this); try { uint channelId; uint messageType = decoder.ReadUInt32(null); int messageLength = (int)decoder.ReadUInt32(null); Debug.Assert(count == messageLength, "Bytes received not equal to encoded Message length"); switch (messageType) { case UaTcpMessageTypes.MSGF: case UaTcpMessageTypes.MSGC: // header channelId = decoder.ReadUInt32(null); if (channelId != this.ChannelId) { throw new ServiceResultException(StatusCodes.BadTcpSecureChannelUnknown); } // symmetric security header var tokenId = decoder.ReadUInt32(null); // detect new token if (tokenId != this.currentServerTokenId) { this.currentServerTokenId = tokenId; // update with new keys if (this.symIsSigned) { this.symVerifier.Key = this.serverSigningKey; if (this.symIsEncrypted) { this.currentServerEncryptingKey = this.serverEncryptingKey; this.currentServerInitializationVector = this.serverInitializationVector; this.symDecryptor = this.symEncryptionAlgorithm.CreateDecryptor(this.currentServerEncryptingKey, this.currentServerInitializationVector); } } } plainHeaderSize = decoder.Position; // decrypt if (this.symIsEncrypted) { using (var symDecryptor = this.symEncryptionAlgorithm.CreateDecryptor(this.currentServerEncryptingKey, this.currentServerInitializationVector)) { int inputCount = messageLength - plainHeaderSize; Debug.Assert(inputCount % symDecryptor.InputBlockSize == 0, "Input data is not an even number of encryption blocks."); symDecryptor.TransformBlock(this.receiveBuffer, plainHeaderSize, inputCount, this.receiveBuffer, plainHeaderSize); symDecryptor.TransformFinalBlock(this.receiveBuffer, messageLength, 0); } } // verify if (this.symIsSigned) { var datalen = messageLength - this.symSignatureSize; byte[] signature = this.symVerifier.ComputeHash(this.receiveBuffer, 0, datalen); if (!signature.SequenceEqual(this.receiveBuffer.AsArraySegment(datalen, this.symSignatureSize))) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed); } } // read sequence header sequenceNumber = decoder.ReadUInt32(null); requestId = decoder.ReadUInt32(null); // body if (this.symIsEncrypted) { if (this.symEncryptionBlockSize > 256) { paddingHeaderSize = 2; paddingSize = BitConverter.ToInt16(this.receiveBuffer, messageLength - this.symSignatureSize - paddingHeaderSize); } else { paddingHeaderSize = 1; paddingSize = this.receiveBuffer[messageLength - this.symSignatureSize - paddingHeaderSize]; } bodySize = messageLength - plainHeaderSize - SequenceHeaderSize - paddingSize - paddingHeaderSize - this.symSignatureSize; } else { bodySize = messageLength - plainHeaderSize - SequenceHeaderSize - this.symSignatureSize; } bodyStream.Write(this.receiveBuffer, plainHeaderSize + SequenceHeaderSize, bodySize); isFinal = messageType == UaTcpMessageTypes.MSGF; break; case UaTcpMessageTypes.OPNF: case UaTcpMessageTypes.OPNC: // header channelId = decoder.ReadUInt32(null); // asymmetric header var securityPolicyUri = decoder.ReadString(null); var serverCertificateByteString = decoder.ReadByteString(null); var clientThumbprint = decoder.ReadByteString(null); plainHeaderSize = decoder.Position; // decrypt if (this.asymIsEncrypted) { byte[] cipherTextBlock = new byte[this.asymLocalCipherTextBlockSize]; int jj = plainHeaderSize; for (int ii = plainHeaderSize; ii < messageLength; ii += this.asymLocalCipherTextBlockSize) { Buffer.BlockCopy(this.receiveBuffer, ii, cipherTextBlock, 0, this.asymLocalCipherTextBlockSize); // decrypt with local private key. byte[] plainTextBlock = this.LocalPrivateKey.Decrypt(cipherTextBlock, this.asymEncryptionPadding); Debug.Assert(plainTextBlock.Length == this.asymLocalPlainTextBlockSize, "Decrypted block length was not as expected."); Buffer.BlockCopy(plainTextBlock, 0, this.receiveBuffer, jj, this.asymLocalPlainTextBlockSize); jj += this.asymLocalPlainTextBlockSize; } messageLength = jj; decoder.Position = plainHeaderSize; } // verify if (this.asymIsSigned) { // verify with remote public key. var datalen = messageLength - this.asymRemoteSignatureSize; if (!this.RemotePublicKey.VerifyData(this.receiveBuffer, 0, datalen, this.receiveBuffer.AsArraySegment(datalen, this.asymRemoteSignatureSize).ToArray(), this.asymSignatureHashAlgorithmName, RSASignaturePadding.Pkcs1)) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed); } } // sequence header sequenceNumber = decoder.ReadUInt32(null); requestId = decoder.ReadUInt32(null); // body if (this.asymIsEncrypted) { if (this.asymLocalCipherTextBlockSize > 256) { paddingHeaderSize = 2; paddingSize = BitConverter.ToInt16(this.receiveBuffer, messageLength - this.asymRemoteSignatureSize - paddingHeaderSize); } else { paddingHeaderSize = 1; paddingSize = this.receiveBuffer[messageLength - this.asymRemoteSignatureSize - paddingHeaderSize]; } bodySize = messageLength - plainHeaderSize - SequenceHeaderSize - paddingSize - paddingHeaderSize - this.asymRemoteSignatureSize; } else { bodySize = messageLength - plainHeaderSize - SequenceHeaderSize - this.asymRemoteSignatureSize; } bodyStream.Write(this.receiveBuffer, plainHeaderSize + SequenceHeaderSize, bodySize); isFinal = messageType == UaTcpMessageTypes.OPNF; break; case UaTcpMessageTypes.ERRF: case UaTcpMessageTypes.MSGA: case UaTcpMessageTypes.OPNA: case UaTcpMessageTypes.CLOA: var code = (StatusCode)decoder.ReadUInt32(null); var message = decoder.ReadString(null); throw new ServiceResultException(code, message); default: throw new ServiceResultException(StatusCodes.BadUnknownResponse); } if (this.LocalMaxMessageSize > 0 && bodyStream.Position > this.LocalMaxMessageSize) { throw new ServiceResultException(StatusCodes.BadEncodingLimitsExceeded); } } finally { decoder.Dispose(); } } while (!isFinal); bodyStream.Seek(0L, SeekOrigin.Begin); var nodeId = bodyDecoder.ReadNodeId(null); IServiceResponse response; // fast path if (nodeId == PublishResponseNodeId) { response = new PublishResponse(); } else if (nodeId == ReadResponseNodeId) { response = new ReadResponse(); } else { // find node in dictionary Type type2; if (!BinaryEncodingIdToTypeDictionary.TryGetValue(NodeId.ToExpandedNodeId(nodeId, this.NamespaceUris), out type2)) { throw new ServiceResultException(StatusCodes.BadEncodingError, "NodeId not registered in dictionary."); } // create response response = (IServiceResponse)Activator.CreateInstance(type2); } // set properties from message stream response.Decode(bodyDecoder); return response; } finally { bodyDecoder.Dispose(); } } finally { this.receivingSemaphore.Release(); } }
protected override async Task OnOpenAsync(CancellationToken token) { token.ThrowIfCancellationRequested(); this.sendBuffer = new byte[MinBufferSize]; this.receiveBuffer = new byte[MinBufferSize]; this.tcpClient = new System.Net.Sockets.TcpClient { NoDelay = true }; var uri = new UriBuilder(this.RemoteEndpoint.EndpointUrl); await this.tcpClient.ConnectAsync(uri.Host, uri.Port).ConfigureAwait(false); this.instream = this.outstream = this.tcpClient.GetStream(); // send 'hello'. int count; var encoder = new BinaryEncoder(new MemoryStream(this.sendBuffer, 0, MinBufferSize, true, false)); try { encoder.WriteUInt32(null, UaTcpMessageTypes.HELF); encoder.WriteUInt32(null, 0u); encoder.WriteUInt32(null, ProtocolVersion); encoder.WriteUInt32(null, this.LocalReceiveBufferSize); encoder.WriteUInt32(null, this.LocalSendBufferSize); encoder.WriteUInt32(null, this.LocalMaxMessageSize); encoder.WriteUInt32(null, this.LocalMaxChunkCount); encoder.WriteString(null, uri.ToString()); count = encoder.Position; encoder.Position = 4; encoder.WriteUInt32(null, (uint)count); encoder.Position = count; await this.SendAsync(this.sendBuffer, 0, count, token).ConfigureAwait(false); } finally { encoder.Dispose(); } // receive response count = await this.ReceiveAsync(this.receiveBuffer, 0, MinBufferSize, token).ConfigureAwait(false); if (count == 0) { throw new ObjectDisposedException("socket"); } // decode 'ack' or 'err'. var decoder = new BinaryDecoder(new MemoryStream(this.receiveBuffer, 0, count, false, false)); try { var type = decoder.ReadUInt32(null); var len = decoder.ReadUInt32(null); if (type == UaTcpMessageTypes.ACKF) { var remoteProtocolVersion = decoder.ReadUInt32(null); if (remoteProtocolVersion < ProtocolVersion) { throw new ServiceResultException(StatusCodes.BadProtocolVersionUnsupported); } this.RemoteSendBufferSize = decoder.ReadUInt32(null); this.RemoteReceiveBufferSize = decoder.ReadUInt32(null); this.RemoteMaxMessageSize = decoder.ReadUInt32(null); this.RemoteMaxChunkCount = decoder.ReadUInt32(null); return; } else if (type == UaTcpMessageTypes.ERRF) { var statusCode = decoder.ReadUInt32(null); var message = decoder.ReadString(null); throw new ServiceResultException(statusCode, message); } throw new InvalidOperationException("UaTcpTransportChannel.OnOpenAsync received unexpected message type."); } finally { decoder.Dispose(); } }