Пример #1
0
        /// <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);
        }
Пример #2
0
 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));
        }
Пример #4
0
        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);
        }
Пример #7
0
        /// <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();
            }
        }
Пример #8
0
        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;
        }
Пример #9
0
        /// <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");
                }
            }
        }
Пример #10
0
        /// <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);
        }
Пример #13
0
        /// <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);
        }
Пример #15
0
        /// <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;
        }