protected void ReadAsymmetricMessageHeader( BinaryDecoder decoder, X509Certificate2 receiverCertificate, out uint secureChannelId, out X509Certificate2Collection senderCertificateChain, out string securityPolicyUri) { senderCertificateChain = null; uint messageType = decoder.ReadUInt32(null); uint messageSize = decoder.ReadUInt32(null); // decode security header. byte[] certificateData = null; byte[] thumbprintData = null; try { secureChannelId = decoder.ReadUInt32(null); securityPolicyUri = decoder.ReadString(null, TcpMessageLimits.MaxSecurityPolicyUriSize); certificateData = decoder.ReadByteString(null, TcpMessageLimits.MaxCertificateSize); thumbprintData = decoder.ReadByteString(null, TcpMessageLimits.CertificateThumbprintSize); } catch (Exception e) { throw ServiceResultException.Create( StatusCodes.BadSecurityChecksFailed, e, "The asymmetric security header could not be parsed."); } // verify sender certificate chain. if (certificateData != null && certificateData.Length > 0) { senderCertificateChain = Utils.ParseCertificateChainBlob(certificateData); try { string thumbprint = senderCertificateChain[0].Thumbprint; if (thumbprint == null) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "Invalid certificate thumbprint."); } } catch (Exception e) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, e, "The sender's certificate could not be parsed."); } } else { if (securityPolicyUri != SecurityPolicies.None) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The sender's certificate was not specified."); } } // verify receiver thumbprint. if (thumbprintData != null && thumbprintData.Length > 0) { if (receiverCertificate.Thumbprint.ToUpperInvariant() != GetThumbprintString(thumbprintData)) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The receiver's certificate thumbprint is not valid."); } } else { if (securityPolicyUri != SecurityPolicies.None) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The receiver's certificate thumbprint was not specified."); } } }
protected void ReadAsymmetricMessageHeader( BinaryDecoder decoder, X509Certificate2 receiverCertificate, out uint secureChannelId, out X509Certificate2 senderCertificate, out string securityPolicyUri) { senderCertificate = null; uint messageType = decoder.ReadUInt32(null); uint messageSize = decoder.ReadUInt32(null); // decode security header. byte[] certificateData = null; byte[] thumbprintData = null; try { secureChannelId = decoder.ReadUInt32(null); securityPolicyUri = decoder.ReadString(null, TcpMessageLimits.MaxSecurityPolicyUriSize); certificateData = decoder.ReadByteString(null, TcpMessageLimits.MaxCertificateSize); thumbprintData = decoder.ReadByteString(null, TcpMessageLimits.CertificateThumbprintSize); } catch (Exception e) { throw ServiceResultException.Create( StatusCodes.BadSecurityChecksFailed, e, "The asymmetric security header could not be parsed."); } // verify sender certificate. if (certificateData != null && certificateData.Length > 0) { senderCertificate = CertificateFactory.Create(certificateData, true); try { string thumbprint = senderCertificate.Thumbprint; if (thumbprint == null) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "Invalid certificate thumbprint."); } } catch (Exception e) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, e, "The sender's certificate could not be parsed."); } } else { if (securityPolicyUri != SecurityPolicies.None) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The sender's certificate was not specified."); } } // verify receiver thumbprint. if (thumbprintData != null && thumbprintData.Length > 0) { if (receiverCertificate.Thumbprint.ToUpperInvariant() != GetThumbprintString(thumbprintData)) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The receiver's certificate thumbprint is not valid."); } } else { if (securityPolicyUri != SecurityPolicies.None) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The receiver's certificate thumbprint was not specified."); } } }
/// <summary> /// Decode a scalar type /// </summary> /// <param name="binaryDecoder"></param> /// <param name="builtInType"></param> /// <returns>The decoded object</returns> private object DecodeRawScalar(BinaryDecoder binaryDecoder, byte builtInType) { switch ((BuiltInType)builtInType) { case BuiltInType.Boolean: return(binaryDecoder.ReadBoolean(null)); case BuiltInType.SByte: return(binaryDecoder.ReadSByte(null)); case BuiltInType.Byte: return(binaryDecoder.ReadByte(null)); case BuiltInType.Int16: return(binaryDecoder.ReadInt16(null)); case BuiltInType.UInt16: return(binaryDecoder.ReadUInt16(null)); case BuiltInType.Int32: return(binaryDecoder.ReadInt32(null)); case BuiltInType.UInt32: return(binaryDecoder.ReadUInt32(null)); case BuiltInType.Int64: return(binaryDecoder.ReadInt64(null)); case BuiltInType.UInt64: return(binaryDecoder.ReadUInt64(null)); case BuiltInType.Float: return(binaryDecoder.ReadFloat(null)); case BuiltInType.Double: return(binaryDecoder.ReadDouble(null)); case BuiltInType.String: return(binaryDecoder.ReadString(null)); case BuiltInType.DateTime: return(binaryDecoder.ReadDateTime(null)); case BuiltInType.Guid: return(binaryDecoder.ReadGuid(null)); case BuiltInType.ByteString: return(binaryDecoder.ReadByteString(null)); case BuiltInType.XmlElement: return(binaryDecoder.ReadXmlElement(null)); case BuiltInType.NodeId: return(binaryDecoder.ReadNodeId(null)); case BuiltInType.ExpandedNodeId: return(binaryDecoder.ReadExpandedNodeId(null)); case BuiltInType.StatusCode: return(binaryDecoder.ReadStatusCode(null)); case BuiltInType.QualifiedName: return(binaryDecoder.ReadQualifiedName(null)); case BuiltInType.LocalizedText: return(binaryDecoder.ReadLocalizedText(null)); case BuiltInType.DataValue: return(binaryDecoder.ReadDataValue(null)); case BuiltInType.Enumeration: return(binaryDecoder.ReadInt32(null)); case BuiltInType.Variant: return(binaryDecoder.ReadVariant(null)); case BuiltInType.ExtensionObject: return(binaryDecoder.ReadExtensionObject(null)); default: return(null); } }
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(); } }