Beispiel #1
0
        private Variant ExecuteTest_AutoReconnect(TestCaseContext testCaseContext, TestCase testCase, int iteration, Variant input)
        {
            if (TestUtils.IsSetupIteration(iteration))
            {
                SetEventSink();
                return(Variant.Null);
            }

            // get the expected input.
            Variant expectedInput;
            int     processingTime = 0;

            lock (m_random)
            {
                Utils.Trace("Iteration {0}; Server Received", iteration);

                // compare actual to expected input.
                m_random.Start(
                    (int)(testCase.Seed + iteration),
                    (int)m_sequenceToExecute.RandomDataStepSize,
                    testCaseContext);

                expectedInput = m_random.GetVariant();

                if (!Compare.CompareVariant(input, expectedInput))
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadUnexpectedError,
                              "Server did not receive expected input\r\nActual = {0}\r\nExpected = {0}",
                              input,
                              expectedInput);
                }

                // determine processing time in server.
                processingTime = m_random.GetInt32Range(0, testCaseContext.MaxResponseDelay);

                if ((iteration + 1) % testCaseContext.StackEventFrequency == 0)
                {
                    if (testCaseContext.StackEventType == 4)
                    {
                        InterruptListener(testCaseContext.StackEventFrequency * testCaseContext.RequestInterval / 2);
                    }

                    StackAction action = TestUtils.GetStackAction(testCaseContext, SecureChannelContext.Current.EndpointDescription);

                    if (action != null)
                    {
                        QueueStackAction(action);
                    }
                }
            }

            // wait.
            Thread.Sleep(processingTime);

            // generate and return the output.
            lock (m_random)
            {
                m_random.Start((int)(
                                   testCase.ResponseSeed + iteration),
                               (int)m_sequenceToExecute.RandomDataStepSize,
                               testCaseContext);

                return(m_random.GetVariant());
            }
        }
Beispiel #2
0
        /// <summary>
        /// Processes an OpenSecureChannel request message.
        /// </summary>
        private bool ProcessOpenSecureChannelRequest(uint messageType, ArraySegment <byte> messageChunk)
        {
            // validate the channel state.
            if (State != TcpChannelState.Opening && State != TcpChannelState.Open)
            {
                ForceChannelFault(StatusCodes.BadTcpMessageTypeInvalid, "Client sent an unexpected OpenSecureChannel message.");
                return(false);
            }

            // parse the security header.
            uint             channelId         = 0;
            X509Certificate2 clientCertificate = null;
            uint             requestId         = 0;
            uint             sequenceNumber    = 0;

            ArraySegment <byte> messageBody;

            try
            {
                messageBody = ReadAsymmetricMessage(
                    messageChunk,
                    ServerCertificate,
                    out channelId,
                    out clientCertificate,
                    out requestId,
                    out sequenceNumber);

                // check for replay attacks.
                if (!VerifySequenceNumber(sequenceNumber, "ProcessOpenSecureChannelRequest"))
                {
                    throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid);
                }
            }
            catch (Exception e)
            {
                ServiceResultException innerException = e.InnerException as ServiceResultException;

                // If the certificate structre, signature and trust list checks pass, we return the other specific validation errors instead of BadSecurityChecksFailed
                if (innerException != null)
                {
                    if (innerException.StatusCode == StatusCodes.BadCertificateUntrusted ||
                        innerException.StatusCode == StatusCodes.BadCertificateChainIncomplete ||
                        innerException.StatusCode == StatusCodes.BadCertificateRevoked ||
                        (innerException.InnerResult != null && innerException.InnerResult.StatusCode == StatusCodes.BadCertificateUntrusted))
                    {
                        ForceChannelFault(StatusCodes.BadSecurityChecksFailed, e.Message);
                        return(false);
                    }
                    else if (innerException.StatusCode == StatusCodes.BadCertificateTimeInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerTimeInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateHostNameInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateUriInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateUseNotAllowed ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerUseNotAllowed ||
                             innerException.StatusCode == StatusCodes.BadCertificateRevocationUnknown ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerRevocationUnknown ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerRevoked)
                    {
                        ForceChannelFault(innerException, innerException.StatusCode, e.Message);
                        return(false);
                    }
                }

                ForceChannelFault(e, StatusCodes.BadSecurityChecksFailed, "Could not verify security on OpenSecureChannel request.");
                return(false);
            }

            BufferCollection chunksToProcess = null;

            try
            {
                bool firstCall = ClientCertificate == null;

                // must ensure the same certificate was used.
                if (ClientCertificate != null)
                {
                    CompareCertificates(ClientCertificate, clientCertificate, false);
                }
                else
                {
                    ClientCertificate = clientCertificate;
                }

                // check if it is necessary to wait for more chunks.
                if (!TcpMessageType.IsFinal(messageType))
                {
                    SaveIntermediateChunk(requestId, messageBody);
                    return(false);
                }

                // create a new token.
                ChannelToken token = CreateToken();

                token.TokenId     = GetNewTokenId();
                token.ServerNonce = CreateNonce();

                // get the chunks to process.
                chunksToProcess = GetSavedChunks(requestId, messageBody);

                OpenSecureChannelRequest request = (OpenSecureChannelRequest)BinaryDecoder.DecodeMessage(
                    new ArraySegmentStream(chunksToProcess),
                    typeof(OpenSecureChannelRequest),
                    Quotas.MessageContext);

                if (request == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadStructureMissing, "Could not parse OpenSecureChannel request body.");
                }

                // check the security mode.
                if (request.SecurityMode != SecurityMode)
                {
                    ReviseSecurityMode(firstCall, request.SecurityMode);
                }

                // check the client nonce.
                token.ClientNonce = request.ClientNonce;

                if (!ValidateNonce(token.ClientNonce))
                {
                    throw ServiceResultException.Create(StatusCodes.BadNonceInvalid, "Client nonce is not the correct length or not random enough.");
                }

                // choose the lifetime.
                int lifetime = (int)request.RequestedLifetime;

                if (lifetime < TcpMessageLimits.MinSecurityTokenLifeTime)
                {
                    lifetime = TcpMessageLimits.MinSecurityTokenLifeTime;
                }

                if (lifetime > 0 && lifetime < token.Lifetime)
                {
                    token.Lifetime = lifetime;
                }

                // check the request type.
                SecurityTokenRequestType requestType = request.RequestType;

                if (requestType == SecurityTokenRequestType.Issue && State != TcpChannelState.Opening)
                {
                    throw ServiceResultException.Create(StatusCodes.BadRequestTypeInvalid, "Cannot request a new token for an open channel.");
                }

                if (requestType == SecurityTokenRequestType.Renew && State != TcpChannelState.Open)
                {
                    // may be reconnecting to a dropped channel.
                    if (State == TcpChannelState.Opening)
                    {
                        // tell the listener to find the channel that can process the request.
                        Listener.ReconnectToExistingChannel(
                            Socket,
                            requestId,
                            sequenceNumber,
                            channelId,
                            ClientCertificate,
                            token,
                            request);

                        Utils.Trace(
                            "{0} ReconnectToExistingChannel Socket={0:X8}, ChannelId={1}, TokenId={2}",
                            ChannelName,
                            (Socket != null) ? Socket.Handle : 0,
                            (CurrentToken != null) ? CurrentToken.ChannelId : 0,
                            (CurrentToken != null) ? CurrentToken.TokenId : 0);

                        // close the channel.
                        ChannelClosed();

                        // nothing more to do.
                        return(false);
                    }

                    throw ServiceResultException.Create(StatusCodes.BadRequestTypeInvalid, "Cannot request to renew a token for a channel that has not been opened.");
                }

                // check the channel id.
                if (requestType == SecurityTokenRequestType.Renew && channelId != ChannelId)
                {
                    throw ServiceResultException.Create(StatusCodes.BadTcpSecureChannelUnknown, "Do not recognize the secure channel id provided.");
                }

                // log security information.
                if (requestType == SecurityTokenRequestType.Issue)
                {
                    Opc.Ua.Security.Audit.SecureChannelCreated(
                        m_ImplementationString,
                        Listener.EndpointUrl.ToString(),
                        Utils.Format("{0}", ChannelId),
                        EndpointDescription,
                        ClientCertificate,
                        ServerCertificate,
                        BinaryEncodingSupport.Required);
                }
                else
                {
                    Opc.Ua.Security.Audit.SecureChannelRenewed(
                        m_ImplementationString,
                        Utils.Format("{0}", ChannelId));
                }

                if (requestType == SecurityTokenRequestType.Renew)
                {
                    SetRenewedToken(token);
                }
                else
                {
                    ActivateToken(token);
                }

                State = TcpChannelState.Open;

                // send the response.
                SendOpenSecureChannelResponse(requestId, token, request);

                // notify reverse
                CompleteReverseHello(null);

                // notify any monitors.
                NotifyMonitors(ServiceResult.Good, false);

                return(false);
            }
            catch (Exception e)
            {
                SendServiceFault(requestId, ServiceResult.Create(e, StatusCodes.BadTcpInternalError, "Unexpected error processing OpenSecureChannel request."));
                CompleteReverseHello(e);
                return(false);
            }
            finally
            {
                if (chunksToProcess != null)
                {
                    chunksToProcess.Release(BufferManager, "ProcessOpenSecureChannelRequest");
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Checks for a valid application instance certificate.
        /// </summary>
        /// <param name="silent">if set to <c>true</c> no dialogs will be displayed.</param>
        /// <param name="minimumKeySize">Minimum size of the key.</param>
        /// <param name="lifeTimeInMonths">The lifetime in months.</param>
        public async Task <bool> CheckApplicationInstanceCertificate(
            bool silent,
            ushort minimumKeySize,
            ushort lifeTimeInMonths)
        {
            Utils.Trace(Utils.TraceMasks.Information, "Checking application instance certificate.");
            if (m_applicationConfiguration == null)
            {
                await LoadApplicationConfiguration(silent).ConfigureAwait(false);
            }

            ApplicationConfiguration configuration = m_applicationConfiguration;
            bool certificateValid = false;

            // find the existing certificate.
            CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate;

            if (id == null)
            {
                throw ServiceResultException.Create(StatusCodes.BadConfigurationError,
                                                    "Configuration file does not specify a certificate.");
            }

            X509Certificate2 certificate = await id.Find(true).ConfigureAwait(false);

            // check that it is ok.
            if (certificate != null)
            {
                certificateValid = await CheckApplicationInstanceCertificate(configuration, certificate, silent, minimumKeySize).ConfigureAwait(false);
            }
            else
            {
                // check for missing private key.
                certificate = await id.Find(false).ConfigureAwait(false);

                if (certificate != null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError,
                                                        "Cannot access certificate private key. Subject={0}", certificate.Subject);
                }

                // check for missing thumbprint.
                if (!String.IsNullOrEmpty(id.Thumbprint))
                {
                    if (!String.IsNullOrEmpty(id.SubjectName))
                    {
                        CertificateIdentifier id2 = new CertificateIdentifier();
                        id2.StoreType   = id.StoreType;
                        id2.StorePath   = id.StorePath;
                        id2.SubjectName = id.SubjectName;
                        certificate     = await id2.Find(true).ConfigureAwait(false);
                    }

                    if (certificate != null)
                    {
                        var message = new StringBuilder();
                        message.AppendLine("Thumbprint was explicitly specified in the configuration.");
                        message.AppendLine("Another certificate with the same subject name was found.");
                        message.AppendLine("Use it instead?");
                        message.AppendLine("Requested: {0}");
                        message.AppendLine("Found: {1}");
                        if (!await ApproveMessage(String.Format(message.ToString(), id.SubjectName, certificate.Subject), silent))
                        {
                            throw ServiceResultException.Create(StatusCodes.BadConfigurationError,
                                                                message.ToString(), id.SubjectName, certificate.Subject);
                        }
                    }
                    else
                    {
                        var message = new StringBuilder();
                        message.AppendLine("Thumbprint was explicitly specified in the configuration. ");
                        message.AppendLine("Cannot generate a new certificate.");
                        throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message.ToString());
                    }
                }
            }

            if ((certificate == null) || !certificateValid)
            {
                certificate = await CreateApplicationInstanceCertificate(configuration,
                                                                         minimumKeySize, lifeTimeInMonths);

                if (certificate == null)
                {
                    var message = new StringBuilder();
                    message.AppendLine("There is no cert with subject {0} in the configuration.");
                    message.AppendLine(" Please generate a cert for your application,");
                    message.AppendLine(" then copy the new cert to this location:");
                    message.AppendLine(" {1}");
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError,
                                                        message.ToString(), id.SubjectName, id.StorePath
                                                        );
                }
            }
            else
            {
                if (configuration.SecurityConfiguration.AddAppCertToTrustedStore)
                {
                    // ensure it is trusted.
                    await AddToTrustedStore(configuration, certificate);
                }
            }

            return(true);
        }
Beispiel #4
0
        /// <summary>
        /// Activates an existing session
        /// </summary>
        public virtual bool ActivateSession(
            OperationContext context,
            NodeId authenticationToken,
            SignatureData clientSignature,
            List <SoftwareCertificate> clientSoftwareCertificates,
            ExtensionObject userIdentityToken,
            SignatureData userTokenSignature,
            StringCollection localeIds,
            out byte[]                      serverNonce)
        {
            serverNonce = null;

            Session           session         = null;
            UserIdentityToken newIdentity     = null;
            UserTokenPolicy   userTokenPolicy = null;

            lock (m_lock)
            {
                // find session.
                if (!m_sessions.TryGetValue(authenticationToken, out session))
                {
                    throw new ServiceResultException(StatusCodes.BadSessionClosed);
                }

                // create new server nonce.
                serverNonce = new byte[m_minNonceLength];
                m_nonceGenerator.GetBytes(serverNonce);

                // validate before activation.
                session.ValidateBeforeActivate(
                    context,
                    clientSignature,
                    clientSoftwareCertificates,
                    userIdentityToken,
                    userTokenSignature,
                    localeIds,
                    serverNonce,
                    out newIdentity,
                    out userTokenPolicy);
            }

            IUserIdentity identity          = null;
            IUserIdentity effectiveIdentity = null;
            ServiceResult error             = null;

            try
            {
                // check if the application has a callback which validates the identity tokens.
                lock (m_eventLock)
                {
                    if (m_ImpersonateUser != null)
                    {
                        ImpersonateEventArgs args = new ImpersonateEventArgs(newIdentity, userTokenPolicy);
                        m_ImpersonateUser(session, args);

                        if (ServiceResult.IsBad(args.IdentityValidationError))
                        {
                            error = args.IdentityValidationError;
                        }
                        else
                        {
                            identity          = args.Identity;
                            effectiveIdentity = args.EffectiveIdentity;
                        }
                    }
                }

                // parse the token manually if the identity is not provided.
                if (identity == null)
                {
                    identity = new UserIdentity(newIdentity);
                }

                // use the identity as the effectiveIdentity if not provided.
                if (effectiveIdentity == null)
                {
                    effectiveIdentity = identity;
                }
            }
            catch (Exception e)
            {
                if (e is ServiceResultException)
                {
                    throw;
                }

                throw ServiceResultException.Create(
                          StatusCodes.BadIdentityTokenInvalid,
                          e,
                          "Could not validate user identity token: {0}",
                          newIdentity);
            }

            // check for validation error.
            if (ServiceResult.IsBad(error))
            {
                throw new ServiceResultException(error);
            }

            // activate session.
            bool contextChanged = session.Activate(
                context,
                clientSoftwareCertificates,
                newIdentity,
                identity,
                effectiveIdentity,
                localeIds,
                serverNonce);

            // raise session related event.
            if (contextChanged)
            {
                RaiseSessionEvent(session, SessionEventReason.Activated);
            }

            // indicates that the identity context for the session has changed.
            return(contextChanged);
        }
        /// <summary>
        /// Updates the security configuration for an application identified by a file or url.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="configuration">The configuration.</param>
        public void WriteConfiguration(string filePath, SecuredApplication configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException("configuration");
            }

            // check for valid file.
            if (String.IsNullOrEmpty(filePath) || !File.Exists(filePath))
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadNotReadable,
                          "Cannot find the configuration file: {0}",
                          configuration.ConfigurationFile);
            }

            // load from file.
            XmlDocument document = new XmlDocument();

            document.Load(filePath);

            XmlElement element = Find(document.DocumentElement, "SecuredApplication", Namespaces.OpcUaSecurity);

            // update secured application.
            if (element != null)
            {
                configuration.LastExportTime = DateTime.UtcNow;
                element.InnerXml             = SetObject(typeof(SecuredApplication), configuration);
            }

            // update application configuration.
            else
            {
                UpdateDocument(document.DocumentElement, configuration);
            }

            try
            {
                // update configuration file.
                Stream        ostrm  = File.Open(filePath, FileMode.Create, FileAccess.Write);
                XmlTextWriter writer = new XmlTextWriter(ostrm, System.Text.Encoding.UTF8);
                writer.Formatting = Formatting.Indented;

                try
                {
                    document.Save(writer);
                }
                finally
                {
                    writer.Close();
                }
            }
            catch (Exception e)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadNotWritable,
                          e,
                          "Cannot update the configuration file: {0}",
                          configuration.ConfigurationFile);
            }
        }
        /// <summary>
        /// This method executes a multi channel test.
        /// </summary>
        /// <param name="testCaseContext">This parameter stores the test case parameter values.</param>
        /// <param name="testCase">This parameter stores the test case related data.</param>
        /// <param name="iteration">This parameter stores the current iteration number.</param>
        /// <param name="input">Input value.</param>
        /// <returns>Input variant.</returns>
        /// <remarks>
        /// The test parameters required for this test case are of the
        /// following types:
        /// <list type="bullet">
        ///     <item>MaxStringLength <see cref="TestCaseContext.MaxStringLength"/></item>
        ///     <item>ChannelsPerServer <see cref="TestCaseContext.ChannelsPerServer"/></item>
        ///     <item>ServerDetails <see cref="TestCaseContext.ServerDetails"/></item>
        /// </list>
        /// </remarks>
        private Variant ExecuteTest_MultipleChannels(TestCaseContext testCaseContext, TestCase testCase, int iteration, Variant input)
        {
            bool isSetupStep = TestUtils.IsSetupIteration(iteration);

            if (!isSetupStep)
            {
                m_logger.LogStartEvent(testCase, iteration);
            }
            try
            {
                if (isSetupStep)
                {
                    // No verification for the input is required.

                    return(Variant.Null);
                }
                else
                {
                    Variant expectedInput;

                    lock (m_random)
                    {
                        m_random.Start(
                            (int)(testCase.Seed + iteration),
                            (int)m_sequenceToExecute.RandomDataStepSize,
                            testCaseContext);

                        expectedInput = m_random.GetScalarVariant(false);
                    }

                    try
                    {
                        if (!Compare.CompareVariant(input, expectedInput))
                        {
                            throw new ServiceResultException(
                                      StatusCodes.BadInvalidState,
                                      Utils.Format("'{0}' is not equal to '{1}'.", input, expectedInput));
                        }
                    }
                    catch (Exception e)
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadInvalidState,
                                  e,
                                  "'{0}' is not equal to '{1}'.", input, expectedInput);
                    }

                    lock (m_random)
                    {
                        m_random.Start((int)(
                                           testCase.ResponseSeed + iteration),
                                       (int)m_sequenceToExecute.RandomDataStepSize,
                                       testCaseContext);

                        return(m_random.GetScalarVariant(false));
                    }
                }
            }
            finally
            {
                if (!isSetupStep)
                {
                    m_logger.LogCompleteEvent(testCase, iteration);
                }
            }
        }
        /// <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;

            // parse the security header.
            ReadAsymmetricMessageHeader(
                decoder,
                receiverCertificate,
                out channelId,
                out senderCertificate,
                out securityPolicyUri);

            // validate the sender certificate.
            if (senderCertificate != null && Quotas.CertificateValidator != null && securityPolicyUri != SecurityPolicies.None)
            {
                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.GetRSAPublicKey().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));
        }
Beispiel #8
0
        /// <summary>
        /// Validates the identity token supplied by the client.
        /// </summary>
        private UserIdentityToken ValidateUserIdentityToken(
            ExtensionObject identityToken,
            SignatureData userTokenSignature,
            out UserTokenPolicy policy)
        {
            policy = null;

            // check for empty token.
            if (identityToken == null || identityToken.Body == null)
            {
                // not changing the token if already activated.
                if (m_activated)
                {
                    return(null);
                }

                // check if an anonymous login is permitted.
                if (m_endpoint.UserIdentityTokens != null && m_endpoint.UserIdentityTokens.Count > 0)
                {
                    bool found = false;

                    for (int ii = 0; ii < m_endpoint.UserIdentityTokens.Count; ii++)
                    {
                        if (m_endpoint.UserIdentityTokens[ii].TokenType == UserTokenType.Anonymous)
                        {
                            found  = true;
                            policy = m_endpoint.UserIdentityTokens[ii];
                            break;
                        }
                    }

                    if (!found)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "Anonymous user token policy not supported.");
                    }
                }

                // create an anonymous token to use for subsequent validation.
                AnonymousIdentityToken anonymousToken = new AnonymousIdentityToken();
                anonymousToken.PolicyId = policy.PolicyId;
                return(anonymousToken);
            }

            UserIdentityToken token = null;

            // check for unrecognized token.
            if (!typeof(UserIdentityToken).IsInstanceOfType(identityToken.Body))
            {
                //handle the use case when the UserIdentityToken is binary encoded over xml message encoding
                if (identityToken.Encoding == ExtensionObjectEncoding.Binary && typeof(byte[]).IsInstanceOfType(identityToken.Body))
                {
                    UserIdentityToken newToken = BaseVariableState.DecodeExtensionObject(null, typeof(UserIdentityToken), identityToken, false) as UserIdentityToken;
                    if (newToken == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "Invalid user identity token provided.");
                    }

                    policy = m_endpoint.FindUserTokenPolicy(newToken.PolicyId);
                    if (policy == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "User token policy not supported.", "Opc.Ua.Server.Session.ValidateUserIdentityToken");
                    }
                    switch (policy.TokenType)
                    {
                    case UserTokenType.Anonymous:
                        token = BaseVariableState.DecodeExtensionObject(null, typeof(AnonymousIdentityToken), identityToken, true) as AnonymousIdentityToken;
                        break;

                    case UserTokenType.UserName:
                        token = BaseVariableState.DecodeExtensionObject(null, typeof(UserNameIdentityToken), identityToken, true) as UserNameIdentityToken;
                        break;

                    case UserTokenType.Certificate:
                        token = BaseVariableState.DecodeExtensionObject(null, typeof(X509IdentityToken), identityToken, true) as X509IdentityToken;
                        break;

                    case UserTokenType.IssuedToken:
                        token = BaseVariableState.DecodeExtensionObject(null, typeof(IssuedIdentityToken), identityToken, true) as IssuedIdentityToken;
                        break;

                    default:
                        throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "Invalid user identity token provided.");
                    }
                }
                else
                {
                    throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "Invalid user identity token provided.");
                }
            }
            else
            {
                // get the token.
                token = (UserIdentityToken)identityToken.Body;
            }

            // find the user token policy.
            policy = m_endpoint.FindUserTokenPolicy(token.PolicyId);

            if (policy == null)
            {
                throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid, "User token policy not supported.");
            }

            // determine the security policy uri.
            string securityPolicyUri = policy.SecurityPolicyUri;

            if (String.IsNullOrEmpty(securityPolicyUri))
            {
                securityPolicyUri = m_endpoint.SecurityPolicyUri;
            }

            if (ServerBase.RequireEncryption(m_endpoint))
            {
                // decrypt the token.
                if (m_serverCertificate == null)
                {
                    m_serverCertificate = CertificateFactory.Create(m_endpoint.ServerCertificate, true);

                    // check for valid certificate.
                    if (m_serverCertificate == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ApplicationCertificate cannot be found.");
                    }
                }

                try
                {
                    token.Decrypt(m_serverCertificate, m_serverNonce, securityPolicyUri);
                }
                catch (Exception e)
                {
                    if (e is ServiceResultException)
                    {
                        throw;
                    }

                    throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid, e, "Could not decrypt identity token.");
                }

                // verify the signature.
                if (securityPolicyUri != SecurityPolicies.None)
                {
                    byte[] dataToSign = Utils.Append(m_serverCertificate.RawData, m_serverNonce);

                    if (!token.Verify(dataToSign, userTokenSignature, securityPolicyUri))
                    {
                        throw new ServiceResultException(StatusCodes.BadUserSignatureInvalid, "Invalid user signature!");
                    }
                }
            }

            // validate user identity token.
            return(token);
        }
        /// <summary>
        /// Starts listening at the specified port.
        /// </summary>
        public void Start()
        {
            lock (m_lock)
            {
                // ensure a valid port.
                int port = m_uri.Port;

                if (port <= 0 || port > UInt16.MaxValue)
                {
                    port = Utils.UaTcpDefaultPort;
                }

                bool            bindToSpecifiedAddress = true;
                UriHostNameType hostType = Uri.CheckHostName(m_uri.Host);
                if (hostType == UriHostNameType.Dns || hostType == UriHostNameType.Unknown || hostType == UriHostNameType.Basic)
                {
                    bindToSpecifiedAddress = false;
                }

                IPAddress ipAddress = IPAddress.Any;
                if (bindToSpecifiedAddress)
                {
                    ipAddress = IPAddress.Parse(m_uri.Host);
                }

                // create IPv4 or IPv6 socket.
                try
                {
                    IPEndPoint endpoint = new IPEndPoint(ipAddress, port);
                    m_listeningSocket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                    args.Completed += OnAccept;
                    args.UserToken  = m_listeningSocket;
                    m_listeningSocket.Bind(endpoint);
                    m_listeningSocket.Listen(Int32.MaxValue);
                    if (!m_listeningSocket.AcceptAsync(args))
                    {
                        OnAccept(null, args);
                    }
                }
                catch (Exception ex)
                {
                    // no IPv4 support.
                    if (m_listeningSocket != null)
                    {
                        m_listeningSocket.Dispose();
                        m_listeningSocket = null;
                    }
                    Utils.Trace("failed to create IPv4 listening socket: " + ex.Message);
                }

                if (ipAddress == IPAddress.Any)
                {
                    // create IPv6 socket
                    try
                    {
                        IPEndPoint endpointIPv6 = new IPEndPoint(IPAddress.IPv6Any, port);
                        m_listeningSocketIPv6 = new Socket(endpointIPv6.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                        SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                        args.Completed += OnAccept;
                        args.UserToken  = m_listeningSocketIPv6;
                        m_listeningSocketIPv6.Bind(endpointIPv6);
                        m_listeningSocketIPv6.Listen(Int32.MaxValue);
                        if (!m_listeningSocketIPv6.AcceptAsync(args))
                        {
                            OnAccept(null, args);
                        }
                    }
                    catch (Exception ex)
                    {
                        // no IPv6 support
                        if (m_listeningSocketIPv6 != null)
                        {
                            m_listeningSocketIPv6.Dispose();
                            m_listeningSocketIPv6 = null;
                        }
                        Utils.Trace("failed to create IPv6 listening socket: " + ex.Message);
                    }
                }
                if (m_listeningSocketIPv6 == null && m_listeningSocket == null)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadNoCommunication,
                              "Failed to establish tcp listener sockets for Ipv4 and IPv6.");
                }
            }
        }
Beispiel #10
0
        /// <summary>
        /// Decrypts the message using RSA PKCS#1 v1.5 encryption.
        /// </summary>
        private ArraySegment <byte> Rsa_Decrypt(
            ArraySegment <byte> dataToDecrypt,
            ArraySegment <byte> headerToCopy,
            X509Certificate2 encryptingCertificate,
            bool useOaep)
        {
            RSA rsa = null;

            try
            {
                // get the encrypting key.
                rsa = encryptingCertificate.GetRSAPrivateKey();
                if (rsa == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate.");
                }

                int inputBlockSize  = RsaUtils.GetCipherTextBlockSize(rsa, useOaep);
                int outputBlockSize = RsaUtils.GetPlainTextBlockSize(rsa, useOaep);

                // verify the input data is the correct block size.
                if (dataToDecrypt.Count % inputBlockSize != 0)
                {
                    Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize);
                }

                byte[] decryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Rsa_Decrypt");
                Array.Copy(headerToCopy.Array, headerToCopy.Offset, decryptedBuffer, 0, headerToCopy.Count);

                using (MemoryStream ostrm = new MemoryStream(
                           decryptedBuffer,
                           headerToCopy.Count,
                           decryptedBuffer.Length - headerToCopy.Count))
                {
                    // decrypt body.
                    byte[] input = new byte[inputBlockSize];

                    for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize)
                    {
                        Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length);
                        if (useOaep == true)
                        {
                            byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1);
                            ostrm.Write(plainText, 0, plainText.Length);
                        }
                        else
                        {
                            byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1);
                            ostrm.Write(plainText, 0, plainText.Length);
                        }
                    }
                }

                // return buffers.
                return(new ArraySegment <byte>(decryptedBuffer, 0, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count));
            }
            finally
            {
                RsaUtils.RSADispose(rsa);
            }
        }
Beispiel #11
0
        /// <summary>
        /// Creates a session with the endpoint.
        /// </summary>
        public Session Connect(ConfiguredEndpoint endpoint)
        {
            if (endpoint == null)
            {
                throw new ArgumentNullException("endpoint");
            }

            EndpointDescriptionCollection availableEndpoints = null;

            // check if the endpoint needs to be updated.
            if (endpoint.UpdateBeforeConnect)
            {
                ConfiguredServerDlg configurationDialog = new ConfiguredServerDlg();
                endpoint = configurationDialog.ShowDialog(endpoint, m_configuration);

                if (endpoint == null)
                {
                    return(null);
                }
                availableEndpoints = configurationDialog.AvailableEnpoints;
            }

            m_endpoint = endpoint;

            // copy the message context.
            m_messageContext = m_configuration.CreateMessageContext();


            X509Certificate2           clientCertificate      = null;
            X509Certificate2Collection clientCertificateChain = null;

            if (endpoint.Description.SecurityPolicyUri != SecurityPolicies.None)
            {
                if (m_configuration.SecurityConfiguration.ApplicationCertificate == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ApplicationCertificate must be specified.");
                }

                clientCertificate = m_configuration.SecurityConfiguration.ApplicationCertificate.Find(true);

                if (clientCertificate == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ApplicationCertificate cannot be found.");
                }

                //load certificate chain
                //clientCertificateChain = new X509Certificate2Collection(clientCertificate);
                //List<CertificateIdentifier> issuers = new List<CertificateIdentifier>();
                //m_configuration.CertificateValidator.GetIssuers(clientCertificate, issuers);
                //for (int i = 0; i < issuers.Count; i++)
                //{
                //    clientCertificateChain.Add(issuers[i].Certificate);
                //}
            }

            // create the channel.
            ITransportChannel channel = SessionChannel.Create(
                m_configuration,
                endpoint.Description,
                endpoint.Configuration,
                //clientCertificateChain,
                clientCertificate,
                m_messageContext);

            // create the session.
            return(Connect(endpoint, channel, availableEndpoints));
        }
            /// <summary>
            /// Validates the identity token supplied by the client.
            /// </summary>
            /// <param name="identityToken"></param>
            /// <param name="userTokenSignature"></param>
            /// <returns></returns>
            private bool ValidateUserIdentityToken(ExtensionObject identityToken,
                                                   SignatureData userTokenSignature)
            {
                UserIdentityToken token = null;
                UserTokenPolicy   policy;

                if (identityToken == null || identityToken.Body == null)
                {
                    if (_activated)
                    {
                        // not changing the token if already activated.
                        return(false);
                    }
                    policy = Endpoint.UserIdentityTokens?
                             .FirstOrDefault(t => t.TokenType == UserTokenType.Anonymous);
                    if (policy == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied,
                                                            "Anonymous user token policy not supported.");
                    }
                    // create an anonymous token to use for subsequent validation.
                    token = new AnonymousIdentityToken {
                        PolicyId = policy.PolicyId
                    };
                }
                else if (!typeof(UserIdentityToken).IsInstanceOfType(identityToken.Body))
                {
                    // Decode identity token from binary.
                    token = DecodeUserIdentityToken(identityToken, out policy);
                }
                else
                {
                    token = (UserIdentityToken)identityToken.Body;
                    // find the user token policy.
                    policy = Endpoint.FindUserTokenPolicy(token.PolicyId);
                    if (policy == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid,
                                                            "User token policy not supported.");
                    }
                }

                // determine the security policy uri.
                var securityPolicyUri = policy.SecurityPolicyUri;

                if (string.IsNullOrEmpty(securityPolicyUri))
                {
                    securityPolicyUri = Endpoint.SecurityPolicyUri;
                }

                if (securityPolicyUri != SecurityPolicies.None)
                {
                    // decrypt the user identity token.
                    if (_serverCertificate == null)
                    {
                        _serverCertificate = CertificateFactory.Create(
                            Endpoint.ServerCertificate, true);
                        // check for valid certificate.
                        if (_serverCertificate == null)
                        {
                            throw ServiceResultException.Create(StatusCodes.BadConfigurationError,
                                                                "ApplicationCertificate cannot be found.");
                        }
                    }
                    try {
                        token.Decrypt(_serverCertificate, _serverNonce, securityPolicyUri);
                    }
                    catch (ServiceResultException) {
                        throw;
                    }
                    catch (Exception e) {
                        throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid,
                                                            e, "Could not decrypt identity token.");
                    }
                    // ... and verify the signature if any.
                    VerifyUserTokenSignature(userTokenSignature, token, securityPolicyUri);
                }

                // We have a valid token - validate it through the handler chain.
                var arg = new UserIdentityHandlerArgs {
                    CurrentIdentities = Identities,
                    Token             = token
                };

                _validator?.Invoke(this, arg);
                if (arg.ValidationException != null)
                {
                    throw arg.ValidationException;
                }
                if (arg.NewIdentities != null)
                {
                    Identities = arg.NewIdentities;
                    return(true);
                }
                return(false); // No new identities
            }
Beispiel #13
0
        /// <summary>
        /// Calls the method.
        /// </summary>
        public void Call()
        {
            // build list of methods to call.
            CallMethodRequestCollection methodsToCall = new CallMethodRequestCollection();

            CallMethodRequest methodToCall = new CallMethodRequest();

            methodToCall.ObjectId = m_objectId;
            methodToCall.MethodId = m_methodId;

            foreach (DataRow row in m_dataset.Tables[0].Rows)
            {
                Argument argument = (Argument)row[0];
                Variant  value    = (Variant)row[4];
                argument.Value = value.Value;
                methodToCall.InputArguments.Add(value);
            }

            methodsToCall.Add(methodToCall);

            // call the method.
            CallMethodResultCollection results         = null;
            DiagnosticInfoCollection   diagnosticInfos = null;

            ResponseHeader responseHeader = m_session.Call(
                null,
                methodsToCall,
                out results,
                out diagnosticInfos);

            ClientBase.ValidateResponse(results, methodsToCall);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, methodsToCall);

            for (int ii = 0; ii < results.Count; ii++)
            {
                // display any input argument errors.
                if (results[ii].InputArgumentResults != null)
                {
                    for (int jj = 0; jj < results[ii].InputArgumentResults.Count; jj++)
                    {
                        if (StatusCode.IsBad(results[ii].InputArgumentResults[jj]))
                        {
                            DataRow row = m_dataset.Tables[0].Rows[jj];
                            row[5]           = results[ii].InputArgumentResults[jj].ToString();
                            ResultCH.Visible = true;
                        }
                    }
                }

                // throw an exception on error.
                if (StatusCode.IsBad(results[ii].StatusCode))
                {
                    throw ServiceResultException.Create(results[ii].StatusCode, ii, diagnosticInfos,
                                                        responseHeader.StringTable);
                }

                // display the output arguments
                ResultCH.Visible      = false;
                NoArgumentsLB.Visible = m_outputArguments == null || m_outputArguments.Length == 0;
                NoArgumentsLB.Text    = "Method invoked successfully.\r\nNo output arguments to display.";
                m_dataset.Tables[0].Rows.Clear();

                if (m_outputArguments != null)
                {
                    for (int jj = 0; jj < m_outputArguments.Length; jj++)
                    {
                        DataRow row = m_dataset.Tables[0].NewRow();

                        if (results[ii].OutputArguments.Count > jj)
                        {
                            UpdateRow(row, m_outputArguments[jj], results[ii].OutputArguments[jj], true);
                        }
                        else
                        {
                            UpdateRow(row, m_outputArguments[jj], Variant.Null, true);
                        }

                        m_dataset.Tables[0].Rows.Add(row);
                    }
                }
            }
        }
Beispiel #14
0
        /// <summary>
        /// Starts listening at the specified port.
        /// </summary>
        public void Start()
        {
            lock (m_lock)
            {
                // ensure a valid port.
                int port = m_uri.Port;

                if (port <= 0 || port > UInt16.MaxValue)
                {
                    port = Utils.UaTcpDefaultPort;
                }

                // create IPv4 socket.
                try
                {
                    IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, port);
                    m_listeningSocket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                    args.Completed += OnAccept;
                    args.UserToken  = m_listeningSocket;
                    m_listeningSocket.Bind(endpoint);
                    m_listeningSocket.Listen(Int32.MaxValue);
                    if (!m_listeningSocket.AcceptAsync(args))
                    {
                        OnAccept(null, args);
                    }
                }
                catch (Exception ex)
                {
                    // no IPv4 support.
                    m_listeningSocket = null;
                    Utils.Trace("failed to create IPv4 listening socket: " + ex.Message);
                }

                // create IPv6 socket
                try
                {
                    IPEndPoint endpointIPv6 = new IPEndPoint(IPAddress.IPv6Any, port);
                    m_listeningSocketIPv6 = new Socket(endpointIPv6.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                    args.Completed += OnAccept;
                    args.UserToken  = m_listeningSocketIPv6;
                    m_listeningSocketIPv6.Bind(endpointIPv6);
                    m_listeningSocketIPv6.Listen(Int32.MaxValue);
                    if (!m_listeningSocketIPv6.AcceptAsync(args))
                    {
                        OnAccept(null, args);
                    }
                }
                catch (Exception ex)
                {
                    // no IPv6 support
                    m_listeningSocketIPv6 = null;
                    Utils.Trace("failed to create IPv6 listening socket: " + ex.Message);
                }

                if (m_listeningSocketIPv6 == null && m_listeningSocket == null)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadNoCommunication,
                              "Failed to establish tcp listener sockets for Ipv4 and IPv6.\r\n");
                }
            }
        }
Beispiel #15
0
        /// <summary>
        /// Sets the application access rules for the specified URL.
        /// </summary>
        public static void SetAccessRules(string url, IList <HttpAccessRule> rules, bool replaceExisting)
        {
            HttpError error = NativeMethods.HttpInitialize(
                new HTTPAPI_VERSION(1, 0),
                HttpInitFlag.HTTP_INITIALIZE_CONFIG,
                IntPtr.Zero);

            if (error != HttpError.NO_ERROR)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadUnexpectedError,
                          "Could not initialize HTTP library.\r\nError={0}",
                          error);
            }

            // fetch existing rules if not replacing them.
            if (!replaceExisting)
            {
                IList <HttpAccessRule> existingRules = GetAccessRules(url);

                if (existingRules.Count > 0)
                {
                    List <HttpAccessRule> mergedRules = new List <HttpAccessRule>(existingRules);
                    mergedRules.AddRange(rules);
                    rules = mergedRules;
                }
            }

            HTTP_SERVICE_CONFIG_URLACL_SET update = new HTTP_SERVICE_CONFIG_URLACL_SET();

            update.KeyDesc.pUrlPrefix = url;
            update.ParamDesc.pStringSecurityDescriptor = FormatSddl(rules);

            IntPtr pStruct    = IntPtr.Zero;
            int    updateSize = Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_URLACL_SET));

            try
            {
                pStruct = Marshal.AllocHGlobal(updateSize);
                NativeMethods.ZeroMemory(pStruct, updateSize);

                Marshal.StructureToPtr(update, pStruct, false);

                error = NativeMethods.HttpDeleteServiceConfiguration(
                    IntPtr.Zero,
                    HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo,
                    pStruct,
                    updateSize,
                    IntPtr.Zero);

                if (error != HttpError.ERROR_FILE_NOT_FOUND && error != HttpError.NO_ERROR)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadUnexpectedError,
                              "Could not delete existing access rules for HTTP url.\r\nError={1}, Url={0}",
                              url,
                              error);
                }

                if (rules.Count > 0)
                {
                    error = NativeMethods.HttpSetServiceConfiguration(
                        IntPtr.Zero,
                        HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo,
                        pStruct,
                        updateSize,
                        IntPtr.Zero);

                    if (error != HttpError.NO_ERROR)
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadUnexpectedError,
                                  "Could not set the access rules for HTTP url.\r\nError={1}, Url={0}",
                                  url,
                                  error);
                    }
                }
            }
            finally
            {
                if (pStruct != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(pStruct, typeof(HTTP_SERVICE_CONFIG_URLACL_SET));
                    Marshal.FreeHGlobal(pStruct);
                }

                NativeMethods.HttpTerminate(HttpInitFlag.HTTP_INITIALIZE_CONFIG, IntPtr.Zero);
            }
        }
Beispiel #16
0
        /// <summary>
        /// Deletes the recent history.
        /// </summary>
        private void DeleteHistory(NodeId areaId, List <VariantCollection> events, FilterDeclaration filter)
        {
            // find the event id.
            int index = 0;

            foreach (FilterDeclarationField field in filter.Fields)
            {
                if (field.InstanceDeclaration.BrowseName == Opc.Ua.BrowseNames.EventId)
                {
                    break;
                }

                index++;
            }

            // can't delete events if no event id.
            if (index >= filter.Fields.Count)
            {
                throw ServiceResultException.Create(StatusCodes.BadEventIdUnknown, "Cannot delete events if EventId was not selected.");
            }

            // build list of nodes to delete.
            DeleteEventDetails details = new DeleteEventDetails();

            details.NodeId = areaId;

            foreach (VariantCollection e in events)
            {
                byte[] eventId = null;

                if (e.Count > index)
                {
                    eventId = e[index].Value as byte[];
                }

                details.EventIds.Add(eventId);
            }

            // delete the events.
            ExtensionObjectCollection nodesToUpdate = new ExtensionObjectCollection();

            nodesToUpdate.Add(new ExtensionObject(details));

            HistoryUpdateResultCollection results         = null;
            DiagnosticInfoCollection      diagnosticInfos = null;

            m_session.HistoryUpdate(
                null,
                nodesToUpdate,
                out results,
                out diagnosticInfos);

            ClientBase.ValidateResponse(results, nodesToUpdate);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToUpdate);

            if (StatusCode.IsBad(results[0].StatusCode))
            {
                throw new ServiceResultException(results[0].StatusCode);
            }

            // check for item level errors.
            if (results[0].OperationResults.Count > 0)
            {
                int count = 0;

                for (int ii = 0; ii < results[0].OperationResults.Count; ii++)
                {
                    if (StatusCode.IsBad(results[0].OperationResults[ii]))
                    {
                        count++;
                    }
                }

                // raise an error.
                if (count > 0)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadEventIdUnknown,
                              "Error deleting events. Only {0} of {1} deletes succeeded.",
                              events.Count - count,
                              events.Count);
                }
            }
        }
Beispiel #17
0
        public static EndpointDescription CreateEndpointDescription(UAServer myServer)
        {
            // create the endpoint description.
            EndpointDescription endpointDescription = null;

            try
            {
                string discoveryUrl = myServer.ServerName;
                //OA 2018-04-27
                if (!discoveryUrl.StartsWith(Utils.UriSchemeOpcTcp) && !discoveryUrl.StartsWith(Utils.UriSchemeHttps))
                //if (!discoveryUrl.StartsWith(Utils.UriSchemeOpcTcp))
                {
                    if (!discoveryUrl.EndsWith("/discovery"))
                    {
                        discoveryUrl += "/discovery";
                    }
                }

                // parse the selected URL.
                Uri uri = new Uri(discoveryUrl);

                // set a short timeout because this is happening in the drop down event.
                EndpointConfiguration configuration = EndpointConfiguration.Create();
                configuration.OperationTimeout = 5000;

                //OA 2018-04-27 https
                if (discoveryUrl.StartsWith(Utils.UriSchemeHttps))
                {
                    configuration.OperationTimeout = 0;
                }
                //

                // Connect to the server's discovery endpoint and find the available configuration.
                using (DiscoveryClient client = DiscoveryClient.Create(uri, configuration))
                {
                    EndpointDescriptionCollection endpoints = client.GetEndpoints(null);

                    // select the best endpoint to use based on the selected URL and the UseSecurity checkbox.
                    for (int ii = 0; ii < endpoints.Count; ii++)
                    {
                        EndpointDescription endpoint = endpoints[ii];

                        // check for a match on the URL scheme.
                        if (endpoint.EndpointUrl.StartsWith(uri.Scheme))
                        {
                            // check if security was requested.
                            if (!myServer.SecurityPolicy.Equals("None"))
                            {
                                if (endpoint.SecurityMode == MessageSecurityMode.None)
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                if (endpoint.SecurityMode != MessageSecurityMode.None)
                                {
                                    continue;
                                }
                            }

                            // pick the first available endpoint by default.
                            if (endpointDescription == null)
                            {
                                endpointDescription = endpoint;
                            }

                            // The security level is a relative measure assigned by the server to the
                            // endpoints that it returns. Clients should always pick the highest level
                            // unless they have a reason not too.
                            if (endpoint.SecurityLevel > endpointDescription.SecurityLevel)
                            {
                                endpointDescription = endpoint;
                            }
                        }
                    }

                    // pick the first available endpoint by default.
                    if (endpointDescription == null && endpoints.Count > 0)
                    {
                        endpointDescription = endpoints[0];
                    }
                }

                // if a server is behind a firewall it may return URLs that are not accessible to the client.
                // This problem can be avoided by assuming that the domain in the URL used to call
                // GetEndpoints can be used to access any of the endpoints. This code makes that conversion.
                // Note that the conversion only makes sense if discovery uses the same protocol as the endpoint.

                Uri endpointUrl = Utils.ParseUri(endpointDescription.EndpointUrl);



                if (endpointUrl != null && endpointUrl.Scheme == uri.Scheme)
                {
                    UriBuilder builder = new UriBuilder(endpointUrl);
                    builder.Host = uri.DnsSafeHost;
                    builder.Port = uri.Port;
                    endpointDescription.EndpointUrl = builder.ToString();
                }
            }
            catch
            {
                endpointDescription             = new EndpointDescription();
                endpointDescription.EndpointUrl = myServer.ServerName;

                //ABA 2014-10-10
                if (myServer.SecurityPolicy.Equals("None"))
                {
                    endpointDescription.SecurityPolicyUri = SecurityPolicies.None;
                }
                //Commented by MM 03/07/2019
                //else if (myServer.SecurityPolicy.Equals("Basic128Rsa15"))
                //{
                //    endpointDescription.SecurityPolicyUri = SecurityPolicies.Basic128Rsa15;
                //}
                else if (myServer.SecurityPolicy.Equals("Basic256Sha256"))
                {
                    endpointDescription.SecurityPolicyUri = SecurityPolicies.Basic256Sha256;
                }
                else if (myServer.SecurityPolicy.Equals("Basic256"))
                {
                    endpointDescription.SecurityPolicyUri = SecurityPolicies.Basic256;
                }

                try
                {
                    MessageSecurityMode myMode;
                    myMode = (MessageSecurityMode)Enum.Parse(typeof(MessageSecurityMode), myServer.SecurityMode, false);
                    //endpointDescription.SecurityMode      = MessageSecurityMode.SignAndEncrypt;
                    endpointDescription.SecurityMode = myMode;
                }
                catch
                {
                    endpointDescription.SecurityMode = MessageSecurityMode.None;
                }

                // specify the transport profile.
                if (myServer.Protocol.Equals("opc.tcp"))
                {
                    endpointDescription.TransportProfileUri = Profiles.UaTcpTransport;
                }
                //added OA 2018-04-27
                else if (myServer.Protocol.Equals("http"))
                {
                    //OA-2018-06-18  endpointDescription.TransportProfileUri = Profiles.WsHttpXmlOrBinaryTransport;
                }
                else //added OA 2018-04-27
                {
                    endpointDescription.TransportProfileUri = Profiles.HttpsBinaryTransport; //OA-2018-06-18 HttpsXmlOrBinaryTransport;
                }
                //else  //OA 2018-04-27
                //{
                //    endpointDescription.TransportProfileUri = Profiles.WsHttpXmlOrBinaryTransport;
                //}

                if (myServer.UserIdentity.Equals(UserIdentityType.Certificate))
                {
                    // load the the server certificate from the local certificate store.
                    CertificateIdentifier certificateIdentifier = new CertificateIdentifier();

                    certificateIdentifier.StoreType = CertificateStoreType.X509Store; //OA-2018-06-18 .Windows;

                    if (!String.IsNullOrEmpty(myServer.CertificationStore))
                    {
                        //certificateIdentifier.StorePath = "LocalMachine\\UA Applications";
                        certificateIdentifier.StorePath = myServer.CertificationStore;
                    }
                    else
                    {
                        using (System.IO.FileStream fs = System.IO.File.OpenRead(myServer.CertificationPath))
                        {
                            byte[] bytes = new byte[fs.Length];
                            fs.Read(bytes, 0, Convert.ToInt32(fs.Length));

                            certificateIdentifier.RawData = bytes;
                        }
                    }

                    //certificateIdentifier.SubjectName = "ONBServer";//commented by HHA 12/11//2019

                    //OA-2018-06-25
                    //X509Certificate2 serverCertificate =  certificateIdentifier.Find();
                    X509Certificate2 serverCertificate = certificateIdentifier.Find().Result;

                    if (serverCertificate == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "Could not find server certificate: {0}", certificateIdentifier.SubjectName);
                    }

                    endpointDescription.ServerCertificate = serverCertificate.GetRawCertData();
                }
            }

            return(endpointDescription);
        }
Beispiel #18
0
        /// <summary>
        /// Writes the asymmetric security header to the buffer.
        /// </summary>
        protected void WriteAsymmetricMessageHeader(
            BinaryEncoder encoder,
            uint messageType,
            uint secureChannelId,
            string securityPolicyUri,
            X509Certificate2 senderCertificate,
            X509Certificate2Collection senderCertificateChain,
            X509Certificate2 receiverCertificate,
            out int senderCertificateSize)
        {
            int start = encoder.Position;

            senderCertificateSize = 0;

            encoder.WriteUInt32(null, messageType);
            encoder.WriteUInt32(null, 0);
            encoder.WriteUInt32(null, secureChannelId);
            encoder.WriteString(null, securityPolicyUri);

            if (SecurityMode != MessageSecurityMode.None)
            {
                if (senderCertificateChain != null && senderCertificateChain.Count > 0)
                {
                    X509Certificate2 currentCertificate  = senderCertificateChain[0];
                    int         maxSenderCertificateSize = GetMaxSenderCertificateSize(currentCertificate, securityPolicyUri);
                    List <byte> senderCertificateList    = new List <byte>(currentCertificate.RawData);
                    senderCertificateSize = currentCertificate.RawData.Length;

                    for (int i = 1; i < senderCertificateChain.Count; i++)
                    {
                        currentCertificate     = senderCertificateChain[i];
                        senderCertificateSize += currentCertificate.RawData.Length;

                        if (senderCertificateSize < maxSenderCertificateSize)
                        {
                            senderCertificateList.AddRange(currentCertificate.RawData);
                        }
                        else
                        {
                            senderCertificateSize -= currentCertificate.RawData.Length;
                            break;
                        }
                    }

                    encoder.WriteByteString(null, senderCertificateList.ToArray());
                }
                else
                {
                    encoder.WriteByteString(null, senderCertificate.RawData);
                }

                encoder.WriteByteString(null, GetThumbprintBytes(receiverCertificate.Thumbprint));
            }
            else
            {
                encoder.WriteByteString(null, null);
                encoder.WriteByteString(null, null);
            }

            if (encoder.Position - start > SendBufferSize)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadInternalError,
                          "AsymmetricSecurityHeader is {0} bytes which is too large for the send buffer size of {1} bytes.",
                          encoder.Position - start,
                          SendBufferSize);
            }
        }
        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.");
                }
            }
        }
Beispiel #20
0
        /// <summary>
        /// Fetches the references for the node.
        /// </summary>
        private List <ReferenceDescription> Browse(Session session, NodeId nodeId)
        {
            List <ReferenceDescription> references = new List <ReferenceDescription>();

            // specify the references to follow and the fields to return.
            BrowseDescription nodeToBrowse = new BrowseDescription();

            nodeToBrowse.NodeId          = nodeId;
            nodeToBrowse.ReferenceTypeId = ReferenceTypeIds.References;
            nodeToBrowse.IncludeSubtypes = true;
            nodeToBrowse.BrowseDirection = BrowseDirection.Both;
            nodeToBrowse.NodeClassMask   = 0;
            nodeToBrowse.ResultMask      = (uint)BrowseResultMask.All;

            BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();

            nodesToBrowse.Add(nodeToBrowse);

            // start the browse operation.
            BrowseResultCollection   results         = null;
            DiagnosticInfoCollection diagnosticInfos = null;

            ResponseHeader responseHeader = session.Browse(
                null,
                null,
                2,
                nodesToBrowse,
                out results,
                out diagnosticInfos);

            // these do sanity checks on the result - make sure response matched the request.
            ClientBase.ValidateResponse(results, nodesToBrowse);
            ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToBrowse);

            // check status.
            if (StatusCode.IsBad(results[0].StatusCode))
            {
                // embed the diagnostic information in a exception.
                throw ServiceResultException.Create(results[0].StatusCode, 0, diagnosticInfos, responseHeader.StringTable);
            }

            // add first batch.
            references.AddRange(results[0].References);

            // check if server limited the results.
            while (results[0].ContinuationPoint != null && results[0].ContinuationPoint.Length > 0)
            {
                ByteStringCollection continuationPoints = new ByteStringCollection();
                continuationPoints.Add(results[0].ContinuationPoint);

                // continue browse operation.
                responseHeader = session.BrowseNext(
                    null,
                    false,
                    continuationPoints,
                    out results,
                    out diagnosticInfos);

                ClientBase.ValidateResponse(results, continuationPoints);
                ClientBase.ValidateDiagnosticInfos(diagnosticInfos, continuationPoints);

                // check status.
                if (StatusCode.IsBad(results[0].StatusCode))
                {
                    // embed the diagnostic information in a exception.
                    throw ServiceResultException.Create(results[0].StatusCode, 0, diagnosticInfos, responseHeader.StringTable);
                }

                // add next batch.
                references.AddRange(results[0].References);
            }

            return(references);
        }
        /// <summary>
        /// Reads the next block of data from the socket.
        /// </summary>
        private void ReadNextBlock()
        {
            Socket socket = null;

            // check if already closed.
            lock (m_socketLock)
            {
                if (m_socket == null)
                {
                    if (m_receiveBuffer != null)
                    {
                        m_bufferManager.ReturnBuffer(m_receiveBuffer, "ReadNextBlock");
                        m_receiveBuffer = null;
                    }

                    return;
                }

                socket = m_socket;

                // avoid stale ServiceException when socket is disconnected
                if (!socket.Connected)
                {
                    return;
                }
            }

            BufferManager.LockBuffer(m_receiveBuffer);

            ServiceResult        error = ServiceResult.Good;
            SocketAsyncEventArgs args  = new SocketAsyncEventArgs();

            try
            {
                args.SetBuffer(m_receiveBuffer, m_bytesReceived, m_bytesToReceive - m_bytesReceived);
                args.Completed += m_ReadComplete;
                if (!socket.ReceiveAsync(args))
                {
                    // I/O completed synchronously
                    if (args.SocketError != SocketError.Success)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadTcpInternalError, args.SocketError.ToString());
                    }
                    else
                    {
                        m_ReadComplete(null, args);
                    }
                }
            }
            catch (ServiceResultException sre)
            {
                args.Dispose();
                BufferManager.UnlockBuffer(m_receiveBuffer);
                throw sre;
            }
            catch (Exception ex)
            {
                args.Dispose();
                BufferManager.UnlockBuffer(m_receiveBuffer);
                throw ServiceResultException.Create(StatusCodes.BadTcpInternalError, ex, "BeginReceive failed.");
            }
        }
Beispiel #22
0
        /// <summary>
        /// Fetches the current SSL certificate configuration.
        /// </summary>
        public static List <SslCertificateBinding> GetSslCertificateBindings()
        {
            List <SslCertificateBinding> bindings = new List <SslCertificateBinding>();

            // initialize library.
            HttpError error = NativeMethods.HttpInitialize(
                new HTTPAPI_VERSION(1, 0),
                HttpInitFlag.HTTP_INITIALIZE_CONFIG,
                IntPtr.Zero);

            if (error != HttpError.NO_ERROR)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadUnexpectedError,
                          "Could not initialize HTTP library.\r\nError={0}",
                          error);
            }

            // set up the iterator.
            HTTP_SERVICE_CONFIG_SSL_QUERY query = new HTTP_SERVICE_CONFIG_SSL_QUERY();

            query.QueryDesc       = HTTP_SERVICE_CONFIG_QUERY_TYPE.HttpServiceConfigQueryNext;
            query.KeyDesc.pIpPort = IntPtr.Zero;

            IntPtr pInput = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_QUERY)));

            NativeMethods.ZeroMemory(pInput, Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_QUERY)));

            IntPtr pOutput = IntPtr.Zero;

            try
            {
                // loop through each record.
                for (query.dwToken = 0; error == HttpError.NO_ERROR; query.dwToken++)
                {
                    // get the size of buffer to allocate.
                    Marshal.StructureToPtr(query, pInput, true);

                    int requiredBufferLength = 0;

                    error = NativeMethods.HttpQueryServiceConfiguration(
                        IntPtr.Zero,
                        HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                        pInput,
                        Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_QUERY)),
                        pOutput,
                        requiredBufferLength,
                        out requiredBufferLength,
                        IntPtr.Zero);

                    if (error == HttpError.ERROR_NO_MORE_ITEMS)
                    {
                        break;
                    }

                    if (error != HttpError.ERROR_INSUFFICIENT_BUFFER)
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadUnexpectedError,
                                  "Could not read SSL configuration information.\r\nError={0}",
                                  error);
                    }

                    // allocate the buffer.
                    pOutput = Marshal.AllocHGlobal(requiredBufferLength);
                    NativeMethods.ZeroMemory(pOutput, requiredBufferLength);

                    // get the actual data.
                    error = NativeMethods.HttpQueryServiceConfiguration(
                        IntPtr.Zero,
                        HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                        pInput,
                        Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_QUERY)),
                        pOutput,
                        requiredBufferLength,
                        out requiredBufferLength,
                        IntPtr.Zero);

                    if (error != HttpError.NO_ERROR)
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadUnexpectedError,
                                  "Could not read SSL configuration information.\r\nError={0}",
                                  error);
                    }

                    HTTP_SERVICE_CONFIG_SSL_SET sslSet = (HTTP_SERVICE_CONFIG_SSL_SET)Marshal.PtrToStructure(pOutput, typeof(HTTP_SERVICE_CONFIG_SSL_SET));

                    short family = Marshal.ReadInt16(sslSet.KeyDesc.pIpPort);
                    SslCertificateBinding binding = new SslCertificateBinding();

                    if (family == AF_INET)
                    {
                        SOCKADDR_IN inet = (SOCKADDR_IN)Marshal.PtrToStructure(sslSet.KeyDesc.pIpPort, typeof(SOCKADDR_IN));
                        binding.IPAddress = new IPAddress(inet.addr);
                        binding.Port      = inet.port;
                    }

                    if (family == AF_INET6)
                    {
                        SOCKADDR_IN6 inet = (SOCKADDR_IN6)Marshal.PtrToStructure(sslSet.KeyDesc.pIpPort, typeof(SOCKADDR_IN6));
                        binding.IPAddress = new IPAddress(inet.addr, inet.scopeID);
                        binding.Port      = inet.port;
                    }

                    binding.Port = (ushort)(((binding.Port & 0xFF00) >> 8) | ((binding.Port & 0x00FF) << 8));

                    byte[] bytes = new byte[sslSet.ParamDesc.SslHashLength];
                    Marshal.Copy(sslSet.ParamDesc.pSslHash, bytes, 0, bytes.Length);

                    binding.Thumbprint                           = Utils.ToHexString(bytes);
                    binding.ApplicationId                        = sslSet.ParamDesc.AppId;
                    binding.StoreName                            = sslSet.ParamDesc.pSslCertStoreName;
                    binding.DefaultCertCheckMode                 = sslSet.ParamDesc.DefaultCertCheckMode;
                    binding.DefaultRevocationFreshnessTime       = sslSet.ParamDesc.DefaultRevocationFreshnessTime;
                    binding.DefaultRevocationUrlRetrievalTimeout = sslSet.ParamDesc.DefaultRevocationUrlRetrievalTimeout;
                    binding.DefaultSslCtlIdentifier              = sslSet.ParamDesc.pDefaultSslCtlIdentifier;
                    binding.DefaultSslCtlStoreName               = sslSet.ParamDesc.pDefaultSslCtlStoreName;
                    binding.DefaultFlags                         = sslSet.ParamDesc.DefaultFlags;

                    bindings.Add(binding);

                    Marshal.FreeHGlobal(pOutput);
                    pOutput = IntPtr.Zero;
                }
            }
            finally
            {
                if (pInput != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(pInput, typeof(HTTP_SERVICE_CONFIG_SSL_QUERY));
                    Marshal.FreeHGlobal(pInput);
                }

                if (pOutput != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pOutput);
                }

                NativeMethods.HttpTerminate(HttpInitFlag.HTTP_INITIALIZE_CONFIG, IntPtr.Zero);
            }

            return(bindings);
        }
Beispiel #23
0
        /// <summary>
        /// Browses the specified node.
        /// </summary>
        public ReferenceDescriptionCollection Browse(NodeId nodeId)
        {
            if (m_session == null)
            {
                throw new ServiceResultException(StatusCodes.BadServerNotConnected, "Cannot browse if not connected to a server.");
            }

            try
            {
                m_browseInProgress = true;

                // construct request.
                BrowseDescription nodeToBrowse = new BrowseDescription();

                nodeToBrowse.NodeId          = nodeId;
                nodeToBrowse.BrowseDirection = m_browseDirection;
                nodeToBrowse.ReferenceTypeId = m_referenceTypeId;
                nodeToBrowse.IncludeSubtypes = m_includeSubtypes;
                nodeToBrowse.NodeClassMask   = m_nodeClassMask;
                nodeToBrowse.ResultMask      = m_resultMask;

                BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();
                nodesToBrowse.Add(nodeToBrowse);

                // make the call to the server.
                BrowseResultCollection   results;
                DiagnosticInfoCollection diagnosticInfos;

                ResponseHeader responseHeader = m_session.Browse(
                    null,
                    m_view,
                    m_maxReferencesReturned,
                    nodesToBrowse,
                    out results,
                    out diagnosticInfos);

                // ensure that the server returned valid results.
                Session.ValidateResponse(results, nodesToBrowse);
                Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToBrowse);

                // check if valid.
                if (StatusCode.IsBad(results[0].StatusCode))
                {
                    throw ServiceResultException.Create(results[0].StatusCode, 0, diagnosticInfos, responseHeader.StringTable);
                }

                // fetch initial set of references.
                byte[] continuationPoint = results[0].ContinuationPoint;
                ReferenceDescriptionCollection references = results[0].References;

                // process any continuation point.
                while (continuationPoint != null)
                {
                    ReferenceDescriptionCollection additionalReferences;

                    if (!m_continueUntilDone && m_MoreReferences != null)
                    {
                        BrowserEventArgs args = new BrowserEventArgs(references);
                        m_MoreReferences(this, args);

                        // cancel browser and return the references fetched so far.
                        if (args.Cancel)
                        {
                            BrowseNext(ref continuationPoint, true);
                            return(references);
                        }

                        m_continueUntilDone = args.ContinueUntilDone;
                    }

                    additionalReferences = BrowseNext(ref continuationPoint, false);
                    if (additionalReferences != null && additionalReferences.Count > 0)
                    {
                        references.AddRange(additionalReferences);
                    }
                    else
                    {
                        Utils.Trace("Continuation point exists, but the browse results are null/empty.");
                        break;
                    }
                }

                // return the results.
                return(references);
            }
            finally
            {
                m_browseInProgress = false;
            }
        }
Beispiel #24
0
        /// <summary>
        /// Creates a new SSL certificate binding.
        /// </summary>
        public static void SetSslCertificateBinding(SslCertificateBinding binding)
        {
            if (binding == null)
            {
                throw new ArgumentNullException("binding");
            }

            // initialize library.
            HttpError error = NativeMethods.HttpInitialize(
                new HTTPAPI_VERSION(1, 0),
                HttpInitFlag.HTTP_INITIALIZE_CONFIG,
                IntPtr.Zero);

            if (error != HttpError.NO_ERROR)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadUnexpectedError,
                          "Could not initialize HTTP library.\r\nError={0}",
                          error);
            }

            IntPtr pAddress    = IntPtr.Zero;
            IntPtr pThumprint  = IntPtr.Zero;
            IntPtr pConfigInfo = IntPtr.Zero;

            try
            {
                pAddress = ToIntPtr(binding.IPAddress, binding.Port);

                byte[] thumbprint = Utils.FromHexString(binding.Thumbprint);
                pThumprint = Marshal.AllocCoTaskMem(thumbprint.Length);
                Marshal.Copy(thumbprint, 0, pThumprint, thumbprint.Length);

                HTTP_SERVICE_CONFIG_SSL_SET configSslSet = new HTTP_SERVICE_CONFIG_SSL_SET();

                configSslSet.KeyDesc.pIpPort                                = pAddress;
                configSslSet.ParamDesc.pSslHash                             = pThumprint;
                configSslSet.ParamDesc.SslHashLength                        = thumbprint.Length;
                configSslSet.ParamDesc.AppId                                = binding.ApplicationId;
                configSslSet.ParamDesc.pSslCertStoreName                    = binding.StoreName;
                configSslSet.ParamDesc.DefaultCertCheckMode                 = binding.DefaultCertCheckMode;
                configSslSet.ParamDesc.DefaultFlags                         = binding.DefaultFlags;
                configSslSet.ParamDesc.DefaultRevocationFreshnessTime       = binding.DefaultRevocationFreshnessTime;
                configSslSet.ParamDesc.DefaultRevocationUrlRetrievalTimeout = binding.DefaultRevocationUrlRetrievalTimeout;
                configSslSet.ParamDesc.pDefaultSslCtlIdentifier             = binding.DefaultSslCtlIdentifier;
                configSslSet.ParamDesc.pDefaultSslCtlStoreName              = binding.DefaultSslCtlStoreName;

                int size = Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_SET));
                pConfigInfo = Marshal.AllocCoTaskMem(size);
                Marshal.StructureToPtr(configSslSet, pConfigInfo, false);

                error = NativeMethods.HttpSetServiceConfiguration(
                    IntPtr.Zero,
                    HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                    pConfigInfo,
                    size,
                    IntPtr.Zero);

                if (error == HttpError.ERROR_ALREADY_EXISTS)
                {
                    error = NativeMethods.HttpDeleteServiceConfiguration(
                        IntPtr.Zero,
                        HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                        pConfigInfo,
                        size,
                        IntPtr.Zero);

                    if (error != HttpError.NO_ERROR)
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadUnexpectedError,
                                  "Could not delete existing SSL certificate binding.\r\nError={0}",
                                  error);
                    }

                    error = NativeMethods.HttpSetServiceConfiguration(
                        IntPtr.Zero,
                        HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                        pConfigInfo,
                        size,
                        IntPtr.Zero);
                }

                if (error != HttpError.NO_ERROR)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadUnexpectedError,
                              "Could not create SSL certificate binding.\r\nError={0}",
                              error);
                }
            }
            finally
            {
                if (pConfigInfo != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pConfigInfo);
                }

                if (pAddress != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pAddress);
                }

                if (pThumprint != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pThumprint);
                }

                NativeMethods.HttpTerminate(HttpInitFlag.HTTP_INITIALIZE_CONFIG, IntPtr.Zero);
            }
        }
        /// <summary>
        /// Exports the security configuration for an application identified by a file or url.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <returns>The security configuration.</returns>
        public SecuredApplication ReadConfiguration(string filePath)
        {
            if (filePath == null)
            {
                throw new ArgumentNullException("filePath");
            }

            string configFilePath = filePath;
            string exeFilePath    = null;

            // check for valid file.
            if (!File.Exists(filePath))
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadNotReadable,
                          "Cannot find the executable or configuration file: {0}",
                          filePath);
            }

            // find the configuration file for the executable.
            if (filePath.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
            {
                exeFilePath = filePath;

                try
                {
                    FileInfo file        = new FileInfo(filePath);
                    string   sectionName = file.Name;
                    sectionName = sectionName.Substring(0, sectionName.Length - file.Extension.Length);

                    System.Configuration.Configuration configuration = ConfigurationManager.OpenExeConfiguration(filePath);

                    configFilePath = ApplicationConfiguration.GetFilePathFromAppConfig(sectionName);

                    if (configFilePath == null)
                    {
                        configFilePath = filePath + ".config";
                    }
                }
                catch (Exception e)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadNotReadable,
                              e,
                              "Cannot find the configuration file for the executable: {0}",
                              filePath);
                }

                if (!File.Exists(configFilePath))
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadNotReadable,
                              "Cannot find the configuration file: {0}",
                              configFilePath);
                }
            }

            SecuredApplication       application = null;
            ApplicationConfiguration applicationConfiguration = null;

            try
            {
                XmlTextReader reader = new XmlTextReader(File.Open(configFilePath, FileMode.Open, FileAccess.Read, FileShare.Read));

                try
                {
                    reader.MoveToContent();

                    // find the SecuredApplication element in the file.
                    if (reader.ReadToDescendant("SecuredApplication", Namespaces.OpcUaSecurity))
                    {
                        DataContractSerializer serializer = new DataContractSerializer(typeof(SecuredApplication));
                        application = serializer.ReadObject(reader, false) as SecuredApplication;

                        application.ConfigurationFile = configFilePath;
                        application.ExecutableFile    = exeFilePath;
                    }

                    // load the application configuration.
                    else
                    {
                        reader.Close();
                        reader = new XmlTextReader(File.Open(configFilePath, FileMode.Open, FileAccess.Read, FileShare.Read));
                        DataContractSerializer serializer = new DataContractSerializer(typeof(ApplicationConfiguration));
                        applicationConfiguration = serializer.ReadObject(reader, false) as ApplicationConfiguration;
                    }
                }
                finally
                {
                    reader.Close();
                }
            }
            catch (Exception e)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadNotReadable,
                          e,
                          "Cannot load the configuration file: {0}",
                          filePath);
            }

            // check if security info store on disk.
            if (application != null)
            {
                return(application);
            }

            application = new SecuredApplication();

            // copy application info.
            application.ApplicationName   = applicationConfiguration.ApplicationName;
            application.ApplicationUri    = applicationConfiguration.ApplicationUri;
            application.ProductName       = applicationConfiguration.ProductUri;
            application.ApplicationType   = (ApplicationType)(int)applicationConfiguration.ApplicationType;
            application.ConfigurationFile = configFilePath;
            application.ExecutableFile    = exeFilePath;
            application.ConfigurationMode = "http://opcfoundation.org/UASDK/ConfigurationTool";
            application.LastExportTime    = DateTime.UtcNow;

            // copy the security settings.
            if (applicationConfiguration.SecurityConfiguration != null)
            {
                application.ApplicationCertificate = SecuredApplication.ToCertificateIdentifier(applicationConfiguration.SecurityConfiguration.ApplicationCertificate);

                if (applicationConfiguration.SecurityConfiguration.TrustedIssuerCertificates != null)
                {
                    application.IssuerCertificateStore = SecuredApplication.ToCertificateStoreIdentifier(applicationConfiguration.SecurityConfiguration.TrustedIssuerCertificates);

                    if (applicationConfiguration.SecurityConfiguration.TrustedIssuerCertificates.TrustedCertificates != null)
                    {
                        application.IssuerCertificates = SecuredApplication.ToCertificateList(applicationConfiguration.SecurityConfiguration.TrustedIssuerCertificates.TrustedCertificates);
                    }
                }

                if (applicationConfiguration.SecurityConfiguration.TrustedPeerCertificates != null)
                {
                    application.TrustedCertificateStore = SecuredApplication.ToCertificateStoreIdentifier(applicationConfiguration.SecurityConfiguration.TrustedPeerCertificates);

                    if (applicationConfiguration.SecurityConfiguration.TrustedPeerCertificates.TrustedCertificates != null)
                    {
                        application.TrustedCertificates = SecuredApplication.ToCertificateList(applicationConfiguration.SecurityConfiguration.TrustedPeerCertificates.TrustedCertificates);
                    }
                }

                if (applicationConfiguration.SecurityConfiguration.RejectedCertificateStore != null)
                {
                    application.RejectedCertificatesStore = SecuredApplication.ToCertificateStoreIdentifier(applicationConfiguration.SecurityConfiguration.RejectedCertificateStore);
                }
            }

            ServerBaseConfiguration serverConfiguration = null;

            if (applicationConfiguration.ServerConfiguration != null)
            {
                serverConfiguration = applicationConfiguration.ServerConfiguration;
            }

            else if (applicationConfiguration.DiscoveryServerConfiguration != null)
            {
                serverConfiguration = applicationConfiguration.DiscoveryServerConfiguration;
            }

            if (serverConfiguration != null)
            {
                application.BaseAddresses    = SecuredApplication.ToListOfBaseAddresses(serverConfiguration);
                application.SecurityProfiles = SecuredApplication.ToListOfSecurityProfiles(serverConfiguration.SecurityPolicies);
            }

            // return exported setttings.
            return(application);
        }
Beispiel #26
0
        /// <summary>
        /// Deletes a new SSL certificate binding.
        /// </summary>
        public static void DeleteSslCertificateBinding(IPAddress address, ushort port)
        {
            if (address == null)
            {
                throw new ArgumentNullException("address");
            }

            // initialize library.
            HttpError error = NativeMethods.HttpInitialize(
                new HTTPAPI_VERSION(1, 0),
                HttpInitFlag.HTTP_INITIALIZE_CONFIG,
                IntPtr.Zero);

            if (error != HttpError.NO_ERROR)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadUnexpectedError,
                          "Could not initialize HTTP library.\r\nError={0}",
                          error);
            }

            IntPtr pAddress    = IntPtr.Zero;
            IntPtr pConfigInfo = IntPtr.Zero;

            try
            {
                pAddress = ToIntPtr(address, port);

                HTTP_SERVICE_CONFIG_SSL_SET configSslSet = new HTTP_SERVICE_CONFIG_SSL_SET();
                configSslSet.KeyDesc.pIpPort = pAddress;

                int size = Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_SET));
                pConfigInfo = Marshal.AllocCoTaskMem(size);
                Marshal.StructureToPtr(configSslSet, pConfigInfo, false);

                error = NativeMethods.HttpDeleteServiceConfiguration(
                    IntPtr.Zero,
                    HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                    pConfigInfo,
                    size,
                    IntPtr.Zero);

                if (error != HttpError.NO_ERROR)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadUnexpectedError,
                              "Could not delete existing SSL certificate binding.\r\nError={0}",
                              error);
                }
            }
            finally
            {
                if (pConfigInfo != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pConfigInfo);
                }

                if (pAddress != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pAddress);
                }

                NativeMethods.HttpTerminate(HttpInitFlag.HTTP_INITIALIZE_CONFIG, IntPtr.Zero);
            }
        }
Beispiel #27
0
        /// <summary>
        /// Processes an CloseSecureChannel request message.
        /// </summary>
        private bool ProcessCloseSecureChannelRequest(uint messageType, ArraySegment <byte> messageChunk)
        {
            // validate security on the message.
            ChannelToken token          = null;
            uint         requestId      = 0;
            uint         sequenceNumber = 0;

            ArraySegment <byte> messageBody;

            try
            {
                messageBody = ReadSymmetricMessage(messageChunk, true, out token, out requestId, out sequenceNumber);

                // check for replay attacks.
                if (!VerifySequenceNumber(sequenceNumber, "ProcessCloseSecureChannelRequest"))
                {
                    throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid);
                }
            }
            catch (Exception e)
            {
                throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, e, "Could not verify security on CloseSecureChannel request.");
            }

            BufferCollection chunksToProcess = null;

            try
            {
                // check if it is necessary to wait for more chunks.
                if (!TcpMessageType.IsFinal(messageType))
                {
                    SaveIntermediateChunk(requestId, messageBody);
                    return(false);
                }

                // get the chunks to process.
                chunksToProcess = GetSavedChunks(requestId, messageBody);

                CloseSecureChannelRequest request = BinaryDecoder.DecodeMessage(
                    new ArraySegmentStream(chunksToProcess),
                    typeof(CloseSecureChannelRequest),
                    Quotas.MessageContext) as CloseSecureChannelRequest;

                if (request == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadStructureMissing, "Could not parse CloseSecureChannel request body.");
                }

                // send the response.
                // SendCloseSecureChannelResponse(requestId, token, request);
            }
            catch (Exception e)
            {
                Utils.Trace(e, "Unexpected error processing OpenSecureChannel request.");
            }
            finally
            {
                if (chunksToProcess != null)
                {
                    chunksToProcess.Release(BufferManager, "ProcessCloseSecureChannelRequest");
                }

                Utils.Trace(
                    "{0} ProcessCloseSecureChannelRequest Socket={0:X8}, ChannelId={1}, TokenId={2}",
                    ChannelName,
                    (Socket != null) ? Socket.Handle : 0,
                    (CurrentToken != null) ? CurrentToken.ChannelId : 0,
                    (CurrentToken != null) ? CurrentToken.TokenId : 0);

                // close the channel.
                ChannelClosed();
            }

            // return false would double free the buffer
            return(true);
        }
Beispiel #28
0
        /// <summary>
        /// Gets the application access rules for the specified URL.
        /// </summary>
        public static IList <HttpAccessRule> GetAccessRules(string url)
        {
            List <HttpAccessRule> accessRules = new List <HttpAccessRule>();

            HttpError error = NativeMethods.HttpInitialize(
                new HTTPAPI_VERSION(1, 0),
                HttpInitFlag.HTTP_INITIALIZE_CONFIG,
                IntPtr.Zero);

            if (error != HttpError.NO_ERROR)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadUnexpectedError,
                          "Could not initialize HTTP library.\r\nError={0}",
                          error);
            }

            HTTP_SERVICE_CONFIG_URLACL_QUERY query = new HTTP_SERVICE_CONFIG_URLACL_QUERY();

            query.QueryDesc = HTTP_SERVICE_CONFIG_QUERY_TYPE.HttpServiceConfigQueryNext;

            if (!String.IsNullOrEmpty(url))
            {
                query.QueryDesc          = HTTP_SERVICE_CONFIG_QUERY_TYPE.HttpServiceConfigQueryExact;
                query.KeyDesc.pUrlPrefix = url;
            }

            IntPtr pInput = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_URLACL_QUERY)));

            NativeMethods.ZeroMemory(pInput, Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_URLACL_QUERY)));

            IntPtr pOutput = IntPtr.Zero;

            try
            {
                for (query.dwToken = 0; error == HttpError.NO_ERROR; query.dwToken++)
                {
                    Marshal.StructureToPtr(query, pInput, true);

                    int requiredBufferLength = 0;

                    error = NativeMethods.HttpQueryServiceConfiguration(
                        IntPtr.Zero,
                        HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo,
                        pInput,
                        Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_URLACL_QUERY)),
                        pOutput,
                        requiredBufferLength,
                        out requiredBufferLength,
                        IntPtr.Zero);

                    if (error == HttpError.ERROR_NO_MORE_ITEMS)
                    {
                        break;
                    }

                    if (!String.IsNullOrEmpty(url))
                    {
                        if (error == HttpError.ERROR_FILE_NOT_FOUND)
                        {
                            break;
                        }
                    }

                    if (error != HttpError.ERROR_INSUFFICIENT_BUFFER)
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadUnexpectedError,
                                  "Could not read access rules for HTTP url.\r\nError={1}, Url={0}",
                                  url,
                                  error);
                    }

                    pOutput = Marshal.AllocHGlobal(requiredBufferLength);
                    NativeMethods.ZeroMemory(pOutput, requiredBufferLength);

                    error = NativeMethods.HttpQueryServiceConfiguration(
                        IntPtr.Zero,
                        HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo,
                        pInput,
                        Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_URLACL_QUERY)),
                        pOutput,
                        requiredBufferLength,
                        out requiredBufferLength,
                        IntPtr.Zero);

                    if (error != HttpError.NO_ERROR)
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadUnexpectedError,
                                  "Could not read access rules for HTTP url.\r\nError={1}, Url={0}",
                                  url,
                                  error);
                    }

                    HTTP_SERVICE_CONFIG_URLACL_SET result = (HTTP_SERVICE_CONFIG_URLACL_SET)Marshal.PtrToStructure(
                        pOutput,
                        typeof(HTTP_SERVICE_CONFIG_URLACL_SET));

                    // parse the SDDL and update the access list.
                    ParseSddl(result.KeyDesc.pUrlPrefix, result.ParamDesc.pStringSecurityDescriptor, accessRules);

                    Marshal.FreeHGlobal(pOutput);
                    pOutput = IntPtr.Zero;

                    // all done if requesting the results for a single url.
                    if (!String.IsNullOrEmpty(url))
                    {
                        break;
                    }
                }
            }
            finally
            {
                if (pInput != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(pInput, typeof(HTTP_SERVICE_CONFIG_URLACL_QUERY));
                    Marshal.FreeHGlobal(pInput);
                }

                if (pOutput != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pOutput);
                }

                NativeMethods.HttpTerminate(HttpInitFlag.HTTP_INITIALIZE_CONFIG, IntPtr.Zero);
            }

            return(accessRules);
        }
Beispiel #29
0
        protected ArraySegment <byte> ReadSymmetricMessage(
            ArraySegment <byte> buffer,
            bool isRequest,
            out ChannelToken token,
            out uint requestId,
            out uint sequenceNumber)
        {
            BinaryDecoder decoder = new BinaryDecoder(buffer.Array, buffer.Offset, buffer.Count, Quotas.MessageContext);

            uint messageType = decoder.ReadUInt32(null);
            uint messageSize = decoder.ReadUInt32(null);
            uint channelId   = decoder.ReadUInt32(null);
            uint tokenId     = decoder.ReadUInt32(null);

            // ensure the channel is valid.
            if (channelId != ChannelId)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadTcpSecureChannelUnknown,
                          "SecureChannelId is not known. ChanneId={0}, CurrentChannelId={1}",
                          channelId,
                          ChannelId);
            }

            // check for a message secured with the new token.
            if (RenewedToken != null && RenewedToken.TokenId == tokenId)
            {
                ActivateToken(RenewedToken);
            }

            // check if activation of the new token should be forced.
            if (RenewedToken != null && CurrentToken.ActivationRequired)
            {
                ActivateToken(RenewedToken);

                Utils.LogInfo("ChannelId {0}: Token #{1} activated forced.", Id, CurrentToken.TokenId);
            }

            // check for valid token.
            ChannelToken currentToken = CurrentToken;

            if (currentToken == null)
            {
                throw new ServiceResultException(StatusCodes.BadSecureChannelClosed);
            }

            // find the token.
            if (currentToken.TokenId != tokenId && PreviousToken != null && PreviousToken.TokenId != tokenId)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadTcpSecureChannelUnknown,
                          "Channel{0}: TokenId is not known. ChanneId={1}, TokenId={2}, CurrentTokenId={3}, PreviousTokenId={4}",
                          Id, channelId,
                          tokenId, currentToken.TokenId,
                          (PreviousToken != null) ? (int)PreviousToken.TokenId : -1);
            }

            token = currentToken;

            // check for a message secured with the token before it expired.
            if (PreviousToken != null && PreviousToken.TokenId == tokenId)
            {
                token = PreviousToken;
            }

            // check if token has expired.
            if (token.Expired)
            {
                throw ServiceResultException.Create(StatusCodes.BadTcpSecureChannelUnknown,
                                                    "Channel{0}: Token #{1} has expired. Lifetime={2:HH:mm:ss.fff}",
                                                    Id, token.TokenId, token.CreatedAt);
            }

            int headerSize = decoder.Position;

            if (SecurityMode == MessageSecurityMode.SignAndEncrypt)
            {
                // decrypt the message.
                Decrypt(token, new ArraySegment <byte>(buffer.Array, buffer.Offset + headerSize, buffer.Count - headerSize), isRequest);
            }

            if (SecurityMode != MessageSecurityMode.None)
            {
                // extract signature.
                byte[] signature = new byte[SymmetricSignatureSize];

                for (int ii = 0; ii < SymmetricSignatureSize; ii++)
                {
                    signature[ii] = buffer.Array[buffer.Offset + buffer.Count - SymmetricSignatureSize + ii];
                }

                // verify the signature.
                if (!Verify(token, signature, new ArraySegment <byte>(buffer.Array, buffer.Offset, buffer.Count - SymmetricSignatureSize), isRequest))
                {
                    Utils.LogError("ChannelId {0}: Could not verify signature on message.", Id);
                    throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the signature on the message.");
                }
            }

            int paddingCount = 0;

            if (SecurityMode == MessageSecurityMode.SignAndEncrypt)
            {
                // verify padding.
                int paddingStart = buffer.Offset + buffer.Count - SymmetricSignatureSize - 1;
                paddingCount = buffer.Array[paddingStart];

                for (int ii = paddingStart - paddingCount; ii < paddingStart; ii++)
                {
                    if (buffer.Array[ii] != paddingCount)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the padding in the message.");
                    }
                }

                // add byte for size.
                paddingCount++;
            }

            // extract request id and sequence number.
            sequenceNumber = decoder.ReadUInt32(null);
            requestId      = decoder.ReadUInt32(null);

            // return an the data contained in the message.
            int startOfBody = buffer.Offset + TcpMessageLimits.SymmetricHeaderSize + TcpMessageLimits.SequenceHeaderSize;
            int sizeOfBody  = buffer.Count - TcpMessageLimits.SymmetricHeaderSize - TcpMessageLimits.SequenceHeaderSize - paddingCount - SymmetricSignatureSize;

            return(new ArraySegment <byte>(buffer.Array, startOfBody, sizeOfBody));
        }
Beispiel #30
0
        /// <summary>
        /// Callback method that will be invoked when the asynchronous BeginTestStack method is complete
        /// </summary>
        private void EndAutoReconnect(IAsyncResult asyncResult)
        {
            AsyncTestState state          = (AsyncTestState)asyncResult.AsyncState;
            long           completionTime = (state.CallData is long)?(long)state.CallData:0;

            lock (m_lock)
            {
                m_requestCount--;

                // check if a fault is expected.
                bool faultExpected = FaultExpected(completionTime, state.TestCaseContext);

                // complete the operation.
                Variant output;

                try
                {
                    state.ChannelContext.ClientSession.EndTestStack(asyncResult, out output);
                }
                catch (Exception e)
                {
                    if (!faultExpected)
                    {
                        // allow faults for a short period of time after a black out ends.
                        for (int ii = 0; ii < m_blackouts.Count; ii++)
                        {
                            if (completionTime >= m_blackouts[ii].Start && completionTime < m_blackouts[ii].End + state.TestCaseContext.MaxTransportDelay)
                            {
                                faultExpected = true;
                                break;
                            }
                        }
                    }

                    for (int ii = 0; ii < m_blackouts.Count; ii++)
                    {
                        long period = m_blackouts[ii].Start;

                        if (m_blackouts[ii].End <= 0)
                        {
                            period = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond - period;
                        }
                        else
                        {
                            period = m_blackouts[ii].End - period;
                        }

                        if (state.TestCaseContext.MaxRecoveryTime + state.TestCaseContext.MaxResponseDelay <= (int)period)
                        {
                            e = ServiceResultException.Create(
                                StatusCodes.BadUnexpectedError,
                                "Iteration {0} MaxRecoveryTime Exceeded {1} ms",
                                state.Iteration,
                                period);

                            faultExpected = false;
                            break;
                        }
                    }

                    // no error if a fault was expected.
                    if (faultExpected)
                    {
                        Utils.Trace("Iteration {0}; Fault Expected {1}", state.Iteration, e.Message);
                        state.ChannelContext.EventLogger.LogCompleteEvent(state.Testcase, state.Iteration);
                        return;
                    }

                    Utils.Trace("Iteration {0}; Fault Unexpected {1}", state.Iteration, e.Message);

                    // log error.
                    state.ChannelContext.EventLogger.LogErrorEvent(state.Testcase, state.Iteration, e);

                    if (m_sequenceToExecute.HaltOnError)
                    {
                        // only report first fault.
                        if (m_fault == null)
                        {
                            m_fault = ServiceResult.Create(e, StatusCodes.BadUnexpectedError, "Unexpected Fault on Iteration {0}", state.Iteration);
                        }
                    }

                    return;
                }

                // allow success for a short period of time before a black out begins.
                for (int ii = 0; ii < m_blackouts.Count; ii++)
                {
                    if ((completionTime <= m_blackouts[ii].End || m_blackouts[ii].End == 0) && completionTime >= m_blackouts[ii].Start - state.TestCaseContext.MaxTransportDelay)
                    {
                        faultExpected = false;
                        break;
                    }
                }

                try
                {
                    // check if a fault was expected.
                    if (faultExpected)
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadUnexpectedError,
                                  "Expecting a fault which did not occur.");
                    }

                    // check processing time.
                    long processingTimeError = ((DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond) - completionTime);

                    Utils.Trace("Iteration {0}; Delta {1}.", state.Iteration, processingTimeError);

                    if (Math.Abs(processingTimeError) > state.TestCaseContext.MaxTransportDelay * 2)
                    {
                        bool late = true;

                        if (state.TestCaseContext.StackEventType == 4)
                        {
                            if (Math.Abs(processingTimeError) > state.TestCaseContext.MaxRecoveryTime)
                            {
                                late = false;
                            }
                        }

                        if (late)
                        {
                            throw ServiceResultException.Create(
                                      StatusCodes.BadUnexpectedError,
                                      "Request did not complete in the specified time (Error = {0}ms).",
                                      processingTimeError);
                        }
                    }

                    // black out ends when the first valid request is returned.
                    for (int ii = 0; ii < m_blackouts.Count; ii++)
                    {
                        if (m_blackouts[ii].End <= 0)
                        {
                            m_blackouts[ii].End = (DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond);
                        }
                    }

                    // check output.
                    state.ChannelContext.Random.Start(
                        (int)(state.Testcase.ResponseSeed + state.Iteration),
                        (int)m_sequenceToExecute.RandomDataStepSize,
                        state.TestCaseContext);

                    Variant expectedOutput = state.ChannelContext.Random.GetVariant();

                    if (!Compare.CompareVariant(output, expectedOutput))
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadUnexpectedError,
                                  "Server did not return expected output\r\nActual = {0}\r\nExpected = {0}",
                                  output,
                                  expectedOutput);
                    }

                    // iteration complete.
                    state.ChannelContext.EventLogger.LogCompleteEvent(state.Testcase, state.Iteration);
                }
                catch (Exception e)
                {
                    state.ChannelContext.EventLogger.LogErrorEvent(state.Testcase, state.Iteration, e);

                    if (m_sequenceToExecute.HaltOnError)
                    {
                        // only report first fault.
                        if (m_fault == null)
                        {
                            m_fault = new ServiceResult(e);
                        }
                    }
                }
            }
        }