/// <summary> /// Extracts the extension object body. /// </summary> /// <param name="value">Extension object.</param> /// <returns>IEncodeable object</returns> public static object GetExtensionObjectBody(ExtensionObject value) { object body = value.Body; IEncodeable encodeable = body as IEncodeable; if (encodeable != null) { return(encodeable); } Type expectedType = EncodeableFactory.GetSystemType(value.TypeId); if (expectedType == null) { return(body); } IServiceMessageContext context = new ServiceMessageContext() { Factory = EncodeableFactory }; XmlElement xml = body as XmlElement; if (xml != null) { XmlQualifiedName xmlName = Opc.Ua.EncodeableFactory.GetXmlName(expectedType); XmlDecoder decoder = new XmlDecoder(xml, context); decoder.PushNamespace(xmlName.Namespace); body = decoder.ReadEncodeable(xmlName.Name, expectedType); decoder.PopNamespace(); decoder.Close(); return((IEncodeable)body); } byte[] bytes = body as byte[]; if (bytes != null) { BinaryDecoder decoder = new BinaryDecoder(bytes, context); body = decoder.ReadEncodeable(null, expectedType); decoder.Close(); return((IEncodeable)body); } return(body); }
private TrustListDataType DecodeTrustListData( ISystemContext context, Stream strm) { TrustListDataType trustList = new TrustListDataType(); ServiceMessageContext messageContext = new ServiceMessageContext() { NamespaceUris = context.NamespaceUris, ServerUris = context.ServerUris, Factory = context.EncodeableFactory }; strm.Position = 0; BinaryDecoder decoder = new BinaryDecoder(strm, messageContext); trustList.Decode(decoder); decoder.Close(); return trustList; }
/// <summary> /// Processes an OpenSecureChannel request message. /// </summary> protected ArraySegment <byte> ReadAsymmetricMessage( ArraySegment <byte> buffer, X509Certificate2 receiverCertificate, out uint channelId, out X509Certificate2 senderCertificate, out uint requestId, out uint sequenceNumber) { BinaryDecoder decoder = new BinaryDecoder(buffer.Array, buffer.Offset, buffer.Count, Quotas.MessageContext); string securityPolicyUri = null; X509Certificate2Collection senderCertificateChain; // parse the security header. ReadAsymmetricMessageHeader( decoder, receiverCertificate, out channelId, out senderCertificateChain, out securityPolicyUri); if (senderCertificateChain != null && senderCertificateChain.Count > 0) { senderCertificate = senderCertificateChain[0]; } else { senderCertificate = null; } // validate the sender certificate. if (senderCertificate != null && Quotas.CertificateValidator != null && securityPolicyUri != SecurityPolicies.None) { CertificateValidator certificateValidator = Quotas.CertificateValidator as CertificateValidator; if (certificateValidator != null) { certificateValidator.Validate(senderCertificateChain); } else { Quotas.CertificateValidator.Validate(senderCertificate); } } // check if this is the first open secure channel request. if (!m_uninitialized) { if (securityPolicyUri != m_securityPolicyUri) { throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "Cannot change the security policy after creating the channnel."); } } else { // find a matching endpoint description. if (m_endpoints != null) { foreach (EndpointDescription endpoint in m_endpoints) { // There may be multiple endpoints with the same securityPolicyUri. // Just choose the first one that matches. This choice will be re-examined // When the OpenSecureChannel request body is processed. if (endpoint.SecurityPolicyUri == securityPolicyUri || (securityPolicyUri == SecurityPolicies.None && endpoint.SecurityMode == MessageSecurityMode.None)) { m_securityMode = endpoint.SecurityMode; m_securityPolicyUri = securityPolicyUri; m_discoveryOnly = false; m_uninitialized = false; m_selectedEndpoint = endpoint; // recalculate the key sizes. CalculateSymmetricKeySizes(); break; } } } // allow a discovery only channel with no security if policy not suppported if (m_uninitialized) { if (securityPolicyUri != SecurityPolicies.None) { throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "The security policy is not supported."); } m_securityMode = MessageSecurityMode.None; m_securityPolicyUri = SecurityPolicies.None; m_discoveryOnly = true; m_uninitialized = false; m_selectedEndpoint = null; } } int headerSize = decoder.Position; // decrypt the body. ArraySegment <byte> plainText = Decrypt( new ArraySegment <byte>(buffer.Array, buffer.Offset + headerSize, buffer.Count - headerSize), new ArraySegment <byte>(buffer.Array, buffer.Offset, headerSize), receiverCertificate); // extract signature. int signatureSize = GetAsymmetricSignatureSize(senderCertificate); byte[] signature = new byte[signatureSize]; for (int ii = 0; ii < signatureSize; ii++) { signature[ii] = plainText.Array[plainText.Offset + plainText.Count - signatureSize + ii]; } // verify the signature. ArraySegment <byte> dataToVerify = new ArraySegment <byte>(plainText.Array, plainText.Offset, plainText.Count - signatureSize); if (!Verify(dataToVerify, signature, senderCertificate)) { Utils.Trace("Could not verify signature on message."); throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the signature on the message."); } // verify padding. int paddingCount = 0; if (SecurityMode != MessageSecurityMode.None) { int paddingEnd = -1; if (CertificateFactory.GetRSAPublicKeySize(receiverCertificate) > TcpMessageLimits.KeySizeExtraPadding) { paddingEnd = plainText.Offset + plainText.Count - signatureSize - 1; paddingCount = plainText.Array[paddingEnd - 1] + plainText.Array[paddingEnd] * 256; //parse until paddingStart-1; the last one is actually the extrapaddingsize for (int ii = paddingEnd - paddingCount; ii < paddingEnd; ii++) { if (plainText.Array[ii] != plainText.Array[paddingEnd - 1]) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the padding in the message."); } } } else { paddingEnd = plainText.Offset + plainText.Count - signatureSize - 1; paddingCount = plainText.Array[paddingEnd]; for (int ii = paddingEnd - paddingCount; ii < paddingEnd; ii++) { if (plainText.Array[ii] != plainText.Array[paddingEnd]) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the padding in the message."); } } } paddingCount++; } // decode message. decoder = new BinaryDecoder( plainText.Array, plainText.Offset + headerSize, plainText.Count - headerSize, Quotas.MessageContext); sequenceNumber = decoder.ReadUInt32(null); requestId = decoder.ReadUInt32(null); headerSize += decoder.Position; decoder.Close(); Utils.Trace("Security Policy: {0}", SecurityPolicyUri); Utils.Trace("Sender Certificate: {0}", (senderCertificate != null) ? senderCertificate.Subject : "(none)"); // return the body. return(new ArraySegment <byte>( plainText.Array, plainText.Offset + headerSize, plainText.Count - headerSize - signatureSize - paddingCount)); }
private bool ProcessHelloMessage(uint messageType, ArraySegment<byte> messageChunk) { // validate the channel state. if (State != TcpChannelState.Connecting) { ForceChannelFault(StatusCodes.BadTcpMessageTypeInvalid, "Client sent an unexpected Hello message."); return false; } try { MemoryStream istrm = new MemoryStream(messageChunk.Array, messageChunk.Offset, messageChunk.Count, false); BinaryDecoder decoder = new BinaryDecoder(istrm, Quotas.MessageContext); istrm.Seek(TcpMessageLimits.MessageTypeAndSize, SeekOrigin.Current); // read requested buffer sizes. uint protocolVersion = decoder.ReadUInt32(null); uint receiveBufferSize = decoder.ReadUInt32(null); uint sendBufferSize = decoder.ReadUInt32(null); uint maxMessageSize = decoder.ReadUInt32(null); uint maxChunkCount = decoder.ReadUInt32(null); // read the endpoint url. int length = decoder.ReadInt32(null); if (length > 0) { if (length > TcpMessageLimits.MaxEndpointUrlLength) { ForceChannelFault(StatusCodes.BadTcpEndpointUrlInvalid); return false; } byte[] endpointUrl = new byte[length]; for (int ii = 0; ii < endpointUrl.Length; ii++) { endpointUrl[ii] = decoder.ReadByte(null); } if (!SetEndpointUrl(new UTF8Encoding().GetString(endpointUrl))) { ForceChannelFault(StatusCodes.BadTcpEndpointUrlInvalid); return false; } } decoder.Close(); // update receive buffer size. if (receiveBufferSize < ReceiveBufferSize) { ReceiveBufferSize = (int)receiveBufferSize; } if (ReceiveBufferSize < TcpMessageLimits.MinBufferSize) { ReceiveBufferSize = TcpMessageLimits.MinBufferSize; } // update send buffer size. if (sendBufferSize < SendBufferSize) { SendBufferSize = (int)sendBufferSize; } if (SendBufferSize < TcpMessageLimits.MinBufferSize) { SendBufferSize = TcpMessageLimits.MinBufferSize; } // update the max message size. if (maxMessageSize > 0 && maxMessageSize < MaxResponseMessageSize) { MaxResponseMessageSize = (int)maxMessageSize; } if (MaxResponseMessageSize < SendBufferSize) { MaxResponseMessageSize = SendBufferSize; } // update the max chunk count. if (maxChunkCount > 0 && maxChunkCount < MaxResponseChunkCount) { MaxResponseChunkCount = (int)maxChunkCount; } // send acknowledge. byte[] buffer = BufferManager.TakeBuffer(SendBufferSize, "ProcessHelloMessage"); try { MemoryStream ostrm = new MemoryStream(buffer, 0, SendBufferSize); BinaryEncoder encoder = new BinaryEncoder(ostrm, Quotas.MessageContext); encoder.WriteUInt32(null, TcpMessageType.Acknowledge); encoder.WriteUInt32(null, 0); encoder.WriteUInt32(null, 0); // ProtocolVersion encoder.WriteUInt32(null, (uint)ReceiveBufferSize); encoder.WriteUInt32(null, (uint)SendBufferSize); encoder.WriteUInt32(null, (uint)MaxRequestMessageSize); encoder.WriteUInt32(null, (uint)MaxRequestChunkCount); int size = encoder.Close(); UpdateMessageSize(buffer, 0, size); // now ready for the open or bind request. State = TcpChannelState.Opening; BeginWriteMessage(new ArraySegment<byte>(buffer, 0, size), Int32.MaxValue, null); buffer = null; } finally { if (buffer != null) { BufferManager.ReturnBuffer(buffer, "ProcessHelloMessage"); } } } catch (Exception e) { ForceChannelFault(e, StatusCodes.BadTcpInternalError, "Unexpected error while processing a Hello message."); } return false; }
/// <summary> /// Reads the trust list. /// </summary> public TrustListDataType ReadTrustList(NodeId trustListId) { if (!IsConnected) { Connect(); } var outputArguments = Session.Call( trustListId, Opc.Ua.MethodIds.FileType_Open, (byte)OpenFileMode.Read); uint fileHandle = (uint)outputArguments[0]; MemoryStream ostrm = new MemoryStream(); try { while (true) { int length = 4096; outputArguments = Session.Call( trustListId, Opc.Ua.MethodIds.FileType_Read, fileHandle, length); byte[] bytes = (byte[])outputArguments[0]; ostrm.Write(bytes, 0, bytes.Length); if (length != bytes.Length) { break; } } } catch (Exception) { throw; } finally { if (IsConnected) { Session.Call( trustListId, Opc.Ua.MethodIds.FileType_Close, fileHandle); } } ostrm.Position = 0; BinaryDecoder decoder = new BinaryDecoder(ostrm, Session.MessageContext); TrustListDataType trustList = new TrustListDataType(); trustList.Decode(decoder); decoder.Close(); ostrm.Close(); return(trustList); }
private bool ProcessHelloMessage(ArraySegment <byte> messageChunk) { // validate the channel state. if (State != TcpChannelState.Connecting) { ForceChannelFault(StatusCodes.BadTcpMessageTypeInvalid, "Client sent an unexpected Hello message."); return(false); } try { MemoryStream istrm = new MemoryStream(messageChunk.Array, messageChunk.Offset, messageChunk.Count, false); BinaryDecoder decoder = new BinaryDecoder(istrm, Quotas.MessageContext); istrm.Seek(TcpMessageLimits.MessageTypeAndSize, SeekOrigin.Current); // read requested buffer sizes. uint protocolVersion = decoder.ReadUInt32(null); uint receiveBufferSize = decoder.ReadUInt32(null); uint sendBufferSize = decoder.ReadUInt32(null); uint maxMessageSize = decoder.ReadUInt32(null); uint maxChunkCount = decoder.ReadUInt32(null); // read the endpoint url. int length = decoder.ReadInt32(null); if (length > 0) { if (length > TcpMessageLimits.MaxEndpointUrlLength) { ForceChannelFault(StatusCodes.BadTcpEndpointUrlInvalid); return(false); } byte[] endpointUrl = new byte[length]; for (int ii = 0; ii < endpointUrl.Length; ii++) { endpointUrl[ii] = decoder.ReadByte(null); } if (!SetEndpointUrl(new UTF8Encoding().GetString(endpointUrl, 0, endpointUrl.Length))) { ForceChannelFault(StatusCodes.BadTcpEndpointUrlInvalid); return(false); } } decoder.Close(); // update receive buffer size. if (receiveBufferSize < ReceiveBufferSize) { ReceiveBufferSize = (int)receiveBufferSize; } if (ReceiveBufferSize < TcpMessageLimits.MinBufferSize) { ReceiveBufferSize = TcpMessageLimits.MinBufferSize; } // update send buffer size. if (sendBufferSize < SendBufferSize) { SendBufferSize = (int)sendBufferSize; } if (SendBufferSize < TcpMessageLimits.MinBufferSize) { SendBufferSize = TcpMessageLimits.MinBufferSize; } // update the max message size. if (maxMessageSize > 0 && maxMessageSize < MaxResponseMessageSize) { MaxResponseMessageSize = (int)maxMessageSize; } if (MaxResponseMessageSize < SendBufferSize) { MaxResponseMessageSize = SendBufferSize; } // update the max chunk count. if (maxChunkCount > 0 && maxChunkCount < MaxResponseChunkCount) { MaxResponseChunkCount = (int)maxChunkCount; } // send acknowledge. byte[] buffer = BufferManager.TakeBuffer(SendBufferSize, "ProcessHelloMessage"); try { MemoryStream ostrm = new MemoryStream(buffer, 0, SendBufferSize); BinaryEncoder encoder = new BinaryEncoder(ostrm, Quotas.MessageContext); encoder.WriteUInt32(null, TcpMessageType.Acknowledge); encoder.WriteUInt32(null, 0); encoder.WriteUInt32(null, 0); // ProtocolVersion encoder.WriteUInt32(null, (uint)ReceiveBufferSize); encoder.WriteUInt32(null, (uint)SendBufferSize); encoder.WriteUInt32(null, (uint)MaxRequestMessageSize); encoder.WriteUInt32(null, (uint)MaxRequestChunkCount); int size = encoder.Close(); UpdateMessageSize(buffer, 0, size); // now ready for the open or bind request. State = TcpChannelState.Opening; BeginWriteMessage(new ArraySegment <byte>(buffer, 0, size), null); buffer = null; } finally { if (buffer != null) { BufferManager.ReturnBuffer(buffer, "ProcessHelloMessage"); } } } catch (Exception e) { ForceChannelFault(e, StatusCodes.BadTcpInternalError, "Unexpected error while processing a Hello message."); } return(false); }
/// <summary> /// Parses the response return from the server. /// </summary> private IServiceResponse ParseResponse(BufferCollection chunksToProcess) { BinaryDecoder decoder = new BinaryDecoder(new ArraySegmentStream(chunksToProcess), Quotas.MessageContext); try { IServiceResponse response = BinaryDecoder.DecodeMessage(new ArraySegmentStream(chunksToProcess), null, Quotas.MessageContext) as IServiceResponse; if (response == null) { throw ServiceResultException.Create(StatusCodes.BadStructureMissing, "Could not parse response body."); } return response; } finally { decoder.Close(); } }
private bool ProcessAcknowledgeMessage(ArraySegment<byte> messageChunk) { // Utils.Trace("Channel {0}: ProcessAcknowledgeMessage()", ChannelId); // check state. if (State != TcpChannelState.Connecting) { ForceReconnect(ServiceResult.Create(StatusCodes.BadTcpMessageTypeInvalid, "Server sent an unexpected acknowledge message.")); return false; } // check if operation was abandoned. if (m_handshakeOperation == null) { return false; } // read buffer sizes. MemoryStream istrm = new MemoryStream(messageChunk.Array, messageChunk.Offset, messageChunk.Count); BinaryDecoder decoder = new BinaryDecoder(istrm, Quotas.MessageContext); istrm.Seek(TcpMessageLimits.MessageTypeAndSize, SeekOrigin.Current); try { uint protocolVersion = decoder.ReadUInt32(null); SendBufferSize = (int)decoder.ReadUInt32(null); ReceiveBufferSize = (int)decoder.ReadUInt32(null); int maxMessageSize = (int)decoder.ReadUInt32(null); int maxChunkCount = (int)decoder.ReadUInt32(null); // update the max message size. if (maxMessageSize > 0 && maxMessageSize < MaxRequestMessageSize) { MaxRequestMessageSize = (int)maxMessageSize; } if (MaxRequestMessageSize < SendBufferSize) { MaxRequestMessageSize = SendBufferSize; } // update the max chunk count. if (maxChunkCount > 0 && maxChunkCount < MaxRequestChunkCount) { MaxRequestChunkCount = (int)maxChunkCount; } } finally { decoder.Close(); } // valdiate buffer sizes. if (ReceiveBufferSize < TcpMessageLimits.MinBufferSize) { m_handshakeOperation.Fault(StatusCodes.BadTcpNotEnoughResources, "Server receive buffer size is too small ({0} bytes).", ReceiveBufferSize); return false; } if (SendBufferSize < TcpMessageLimits.MinBufferSize) { m_handshakeOperation.Fault(StatusCodes.BadTcpNotEnoughResources, "Server send buffer size is too small ({0} bytes).", SendBufferSize); return false; } // ready to open the channel. State = TcpChannelState.Opening; try { // check if reconnecting after a socket failure. if (CurrentToken != null) { SendOpenSecureChannelRequest(true); return false; } // open a new connection. SendOpenSecureChannelRequest(false); } catch (Exception e) { m_handshakeOperation.Fault(e, StatusCodes.BadTcpInternalError, "Could not send an Open Secure Channel request."); } return false; }
/// <summary> /// Processes a response message. /// </summary> private bool ProcessResponseMessage(uint messageType, ArraySegment<byte> messageChunk) { // Utils.Trace("Channel {0}: ProcessResponseMessage()", ChannelId); // validate security on the message. TcpChannelToken token = null; uint requestId = 0; uint sequenceNumber = 0; ArraySegment<byte> messageBody; try { messageBody = ReadSymmetricMessage(messageChunk, false, out token, out requestId, out sequenceNumber); } catch (Exception e) { ForceReconnect(ServiceResult.Create(e, StatusCodes.BadSecurityChecksFailed, "Could not verify security on response.")); return false; } // check if operation is still available. WriteOperation operation = null; if (!m_requests.TryGetValue(requestId, out operation)) { return false; } BufferCollection chunksToProcess = null; // check for replay attacks. if (!VerifySequenceNumber(sequenceNumber, "ProcessResponseMessage")) { throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid); } try { // check for an abort. if (TcpMessageType.IsAbort(messageType)) { // get the chunks to process. chunksToProcess = GetSavedChunks(requestId, messageBody); // decoder reason. MemoryStream istrm = new MemoryStream(messageBody.Array, messageBody.Offset, messageBody.Count, false); BinaryDecoder decoder = new BinaryDecoder(istrm, Quotas.MessageContext); ServiceResult error = ReadErrorMessageBody(decoder); decoder.Close(); // report a fault. operation.Fault(true, error); return true; } // check if it is necessary to wait for more chunks. if (!TcpMessageType.IsFinal(messageType)) { SaveIntermediateChunk(requestId, messageBody); return true; } // get the chunks to process. chunksToProcess = GetSavedChunks(requestId, messageBody); // get response. operation.MessageBody = ParseResponse(chunksToProcess); if (operation.MessageBody == null) { operation.Fault(true, StatusCodes.BadStructureMissing, "Could not parse response body."); return true; } // is complete. operation.Complete(true, 0); return true; } catch (Exception e) { operation.Fault(true, e, StatusCodes.BadUnknownResponse, "Unexpected error processing response."); return true; } finally { if (chunksToProcess != null) { chunksToProcess.Release(BufferManager, "ProcessResponseMessage"); } } }
/// <summary> /// Processes an Error message received over the socket. /// </summary> protected bool ProcessErrorMessage(uint messageType, ArraySegment<byte> messageChunk) { // Utils.Trace("Channel {0}: ProcessErrorMessage()", ChannelId); // read request buffer sizes. MemoryStream istrm = new MemoryStream(messageChunk.Array, messageChunk.Offset, messageChunk.Count, false); BinaryDecoder decoder = new BinaryDecoder(istrm, Quotas.MessageContext); istrm.Seek(TcpMessageLimits.MessageTypeAndSize, SeekOrigin.Current); try { ServiceResult error = ReadErrorMessageBody(decoder); // check if a handshake is in progress if (m_handshakeOperation != null) { m_handshakeOperation.Fault(error); return false; } // handle the fatal error. ForceReconnect(error); return false; } finally { decoder.Close(); } }
/// <summary> /// Reads the trust list. /// </summary> public TrustListDataType ReadTrustList(TrustListMasks masks = TrustListMasks.All) { if (!IsConnected) { Connect(); } IUserIdentity oldUser = ElevatePermissions(); try { var outputArguments = m_session.Call( ExpandedNodeId.ToNodeId(Opc.Ua.ObjectIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup_TrustList, m_session.NamespaceUris), ExpandedNodeId.ToNodeId(Opc.Ua.MethodIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup_TrustList_OpenWithMasks, m_session.NamespaceUris), (uint)masks); uint fileHandle = (uint)outputArguments[0]; MemoryStream ostrm = new MemoryStream(); try { while (true) { int length = 256; outputArguments = m_session.Call( ExpandedNodeId.ToNodeId(Opc.Ua.ObjectIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup_TrustList, m_session.NamespaceUris), ExpandedNodeId.ToNodeId(Opc.Ua.MethodIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup_TrustList_Read, m_session.NamespaceUris), fileHandle, length); byte[] bytes = (byte[])outputArguments[0]; ostrm.Write(bytes, 0, bytes.Length); if (length != bytes.Length) { break; } } m_session.Call( ExpandedNodeId.ToNodeId(Opc.Ua.ObjectIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup_TrustList, m_session.NamespaceUris), ExpandedNodeId.ToNodeId(Opc.Ua.MethodIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup_TrustList_Close, m_session.NamespaceUris), fileHandle); } catch (Exception) { if (IsConnected) { m_session.Call( ExpandedNodeId.ToNodeId(Opc.Ua.ObjectIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup_TrustList, m_session.NamespaceUris), ExpandedNodeId.ToNodeId(Opc.Ua.MethodIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup_TrustList_Close, m_session.NamespaceUris), fileHandle); } throw; } ostrm.Position = 0; BinaryDecoder decoder = new BinaryDecoder(ostrm, m_session.MessageContext); TrustListDataType trustList = new TrustListDataType(); trustList.Decode(decoder); decoder.Close(); ostrm.Close(); return(trustList); } finally { RevertPermissions(oldUser); } }
/// <summary> /// Processes an OpenSecureChannel request message. /// </summary> protected ArraySegment<byte> ReadAsymmetricMessage( ArraySegment<byte> buffer, X509Certificate2 receiverCertificate, out uint channelId, out X509Certificate2 senderCertificate, out uint requestId, out uint sequenceNumber) { BinaryDecoder decoder = new BinaryDecoder(buffer.Array, buffer.Offset, buffer.Count, Quotas.MessageContext); string securityPolicyUri = null; //X509Certificate2Collection senderCertificateChain; // parse the security header. ReadAsymmetricMessageHeader( decoder, receiverCertificate, out channelId, out senderCertificate, out securityPolicyUri); /*senderCertificate = null; if (senderCertificateChain != null && senderCertificateChain.Count > 0) { senderCertificate = senderCertificateChain[0]; }*/ // validate the sender certificate. if (senderCertificate != null && Quotas.CertificateValidator != null && securityPolicyUri != SecurityPolicies.None) { //(Quotas.CertificateValidator as Opc.Ua.CertificateValidator.WcfValidatorWrapper).Validate(senderCertificateChain); Quotas.CertificateValidator.Validate(senderCertificate); } // check if this is the first open secure channel request. if (!m_uninitialized) { if (securityPolicyUri != m_securityPolicyUri) { throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "Cannot change the security policy after creating the channnel."); } } else { // find a matching endpoint description. if (m_endpoints != null) { foreach (EndpointDescription endpoint in m_endpoints) { // There may be multiple endpoints with the same securityPolicyUri. // Just choose the first one that matches. This choice will be re-examined // When the OpenSecureChannel request body is processed. if (endpoint.SecurityPolicyUri == securityPolicyUri || (securityPolicyUri == SecurityPolicies.None && endpoint.SecurityMode == MessageSecurityMode.None)) { m_securityMode = endpoint.SecurityMode; m_securityPolicyUri = securityPolicyUri; m_discoveryOnly = false; m_uninitialized = false; m_selectedEndpoint = endpoint; // recalculate the key sizes. CalculateSymmetricKeySizes(); break; } } } // allow a discovery only channel with no security if policy not suppported if (m_uninitialized) { if (securityPolicyUri != SecurityPolicies.None) { throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "The security policy is not supported."); } m_securityMode = MessageSecurityMode.None; m_securityPolicyUri = SecurityPolicies.None; m_discoveryOnly = true; m_uninitialized = false; m_selectedEndpoint = null; } } int headerSize = decoder.Position; // decrypt the body. ArraySegment<byte> plainText = Decrypt( new ArraySegment<byte>(buffer.Array, buffer.Offset + headerSize, buffer.Count - headerSize), new ArraySegment<byte>(buffer.Array, buffer.Offset, headerSize), receiverCertificate); // extract signature. int signatureSize = GetAsymmetricSignatureSize(senderCertificate); byte[] signature = new byte[signatureSize]; for (int ii = 0; ii < signatureSize; ii++) { signature[ii] = plainText.Array[plainText.Offset+plainText.Count-signatureSize+ii]; } // verify the signature. ArraySegment<byte> dataToVerify = new ArraySegment<byte>(plainText.Array, plainText.Offset, plainText.Count-signatureSize); if (!Verify(dataToVerify, signature, senderCertificate)) { Utils.Trace("Could not verify signature on message."); throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the signature on the message."); } // verify padding. int paddingCount = 0; if (SecurityMode != MessageSecurityMode.None) { int paddingEnd = -1; if (receiverCertificate.PublicKey.Key.KeySize > TcpMessageLimits.KeySizeExtraPadding) { paddingEnd = plainText.Offset + plainText.Count - signatureSize - 1; paddingCount = plainText.Array[paddingEnd - 1] + plainText.Array[paddingEnd] * 256; //parse until paddingStart-1; the last one is actually the extrapaddingsize for (int ii = paddingEnd - paddingCount; ii < paddingEnd; ii++) { if (plainText.Array[ii] != plainText.Array[paddingEnd - 1]) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the padding in the message."); } } } else { paddingEnd = plainText.Offset + plainText.Count - signatureSize - 1; paddingCount = plainText.Array[paddingEnd]; for (int ii = paddingEnd - paddingCount; ii < paddingEnd; ii++) { if (plainText.Array[ii] != plainText.Array[paddingEnd]) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the padding in the message."); } } } paddingCount++; } // decode message. decoder = new BinaryDecoder( plainText.Array, plainText.Offset + headerSize, plainText.Count - headerSize, Quotas.MessageContext); sequenceNumber = decoder.ReadUInt32(null); requestId = decoder.ReadUInt32(null); headerSize += decoder.Position; decoder.Close(); // Utils.Trace("Security Policy: {0}", SecurityPolicyUri); // Utils.Trace("Sender Certificate: {0}", (senderCertificate != null)?senderCertificate.Subject:"(none)"); // return the body. return new ArraySegment<byte>( plainText.Array, plainText.Offset + headerSize, plainText.Count - headerSize - signatureSize - paddingCount); }
/// <summary> /// Acknowledges the specified context. /// </summary> /// <param name="context">The context.</param> /// <param name="eventId">The event id.</param> /// <param name="comment">The comment.</param> /// <returns></returns> public uint Acknowledge( ServerSystemContext context, byte[] eventId, LocalizedText comment) { // get the user name from the context. string userName = String.Empty; if (context.UserIdentity != null) { userName = context.UserIdentity.DisplayName; } // get the comment. string commentText = String.Empty; if (comment != null) { commentText = comment.Text; } System.Runtime.InteropServices.ComTypes.FILETIME ftActiveTime; // unpack the event id. ServiceMessageContext messageContext = new ServiceMessageContext(); messageContext.NamespaceUris = context.NamespaceUris; messageContext.ServerUris = context.ServerUris; messageContext.Factory = context.EncodeableFactory; BinaryDecoder decoder = new BinaryDecoder(eventId, messageContext); string source = decoder.ReadString(null); string conditionName = decoder.ReadString(null); ftActiveTime.dwHighDateTime = decoder.ReadInt32(null); ftActiveTime.dwLowDateTime = decoder.ReadInt32(null); int cookie = decoder.ReadInt32(null); decoder.Close(); string methodName = "IOPCEventServer.AckCondition"; IntPtr pErrors = IntPtr.Zero; try { IOPCEventServer server = BeginComCall <IOPCEventServer>(methodName, true); server.AckCondition( 1, userName, commentText, new string[] { source }, new string[] { conditionName }, new System.Runtime.InteropServices.ComTypes.FILETIME[] { ftActiveTime }, new int[] { cookie }, out pErrors); } catch (Exception e) { ComCallError(methodName, e); return(StatusCodes.BadUnexpectedError); } finally { EndComCall(methodName); } // unmarshal results. int[] errors = ComUtils.GetInt32s(ref pErrors, 1, true); if (errors[0] == ResultIds.S_ALREADYACKED) { return(StatusCodes.BadConditionBranchAlreadyAcked); } else if (errors[0] < 0) { return(StatusCodes.BadEventIdUnknown); } return(StatusCodes.Good); }
/// <summary> /// Converts a local value to a remote value. /// </summary> /// <param name="srcValue">The local value.</param> /// <param name="srcType">The data type of the local value.</param> /// <param name="dstType">The data type of the remote value.</param> /// <returns>The remote value.</returns> private object ConvertLocalToRemote(object srcValue, BuiltInType srcType, BuiltInType dstType) { // must determine the type from the source if the containing array is a variant. if (srcType == BuiltInType.Variant) { TypeInfo typeInfo = TypeInfo.Construct(srcValue); srcType = typeInfo.BuiltInType; } // no conversion by default. object dstValue = srcValue; // apply different conversions depending on the data type. switch (dstType) { case BuiltInType.Guid: { dstValue = new Uuid((string)srcValue); break; } case BuiltInType.XmlElement: { XmlDocument document = new XmlDocument(); document.InnerXml = (string)srcValue; dstValue = document.DocumentElement; break; } case BuiltInType.NodeId: { dstValue = GetRemoteNodeId((string)srcValue); break; } case BuiltInType.ExpandedNodeId: { ExpandedNodeId nodeId = ExpandedNodeId.Parse((string)srcValue); dstValue = GetRemoteExpandedNodeId(nodeId); break; } case BuiltInType.QualifiedName: { dstValue = GetRemoteBrowseName((string)srcValue); break; } case BuiltInType.LocalizedText: { dstValue = new LocalizedText((string)srcValue); break; } case BuiltInType.StatusCode: { dstValue = new StatusCode((uint)srcValue); break; } case BuiltInType.ExtensionObject: { BinaryDecoder decoder = new BinaryDecoder((byte[])srcValue, m_localMessageContext); dstValue = decoder.ReadExtensionObject(null); decoder.Close(); break; } default: { if (dstType != srcType && dstType != BuiltInType.Variant && dstType != BuiltInType.Null) { throw ComUtils.CreateComException(ResultIds.E_BADTYPE); } break; } } // all done. return(dstValue); }
/// <summary> /// Converts a local value to a remote value. /// </summary> /// <param name="srcValue">The local value.</param> /// <param name="srcType">The data type of the local value.</param> /// <param name="dstType">The data type of the remote value.</param> /// <returns>The remote value.</returns> private object ConvertLocalToRemote(object srcValue, BuiltInType srcType, BuiltInType dstType) { // must determine the type from the source if the containing array is a variant. if (srcType == BuiltInType.Variant) { TypeInfo typeInfo = TypeInfo.Construct(srcValue); srcType = typeInfo.BuiltInType; } // no conversion by default. object dstValue = srcValue; // apply different conversions depending on the data type. switch (dstType) { case BuiltInType.Guid: { dstValue = new Uuid((string)srcValue); break; } case BuiltInType.XmlElement: { XmlDocument document = new XmlDocument(); document.InnerXml = (string)srcValue; dstValue = document.DocumentElement; break; } case BuiltInType.NodeId: { dstValue = GetRemoteNodeId((string)srcValue); break; } case BuiltInType.ExpandedNodeId: { ExpandedNodeId nodeId = ExpandedNodeId.Parse((string)srcValue); dstValue = GetRemoteExpandedNodeId(nodeId); break; } case BuiltInType.QualifiedName: { dstValue = GetRemoteBrowseName((string)srcValue); break; } case BuiltInType.LocalizedText: { dstValue = new LocalizedText((string)srcValue); break; } case BuiltInType.StatusCode: { dstValue = new StatusCode((uint)srcValue); break; } case BuiltInType.ExtensionObject: { BinaryDecoder decoder = new BinaryDecoder((byte[])srcValue, m_localMessageContext); dstValue = decoder.ReadExtensionObject(null); decoder.Close(); break; } default: { if (dstType != srcType && dstType != BuiltInType.Variant && dstType != BuiltInType.Null) { throw ComUtils.CreateComException(ResultIds.E_BADTYPE); } break; } } // all done. return dstValue; }