Ejemplo n.º 1
0
        /// <summary>
        /// Processes an CloseSecureChannel request message.
        /// </summary>
        private bool ProcessCloseSecureChannelRequest(uint messageType, ArraySegment <byte> messageChunk)
        {
            // validate security on the message.
            TcpChannelToken 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(
                    "TCPSERVERCHANNEL ProcessCloseSecureChannelRequest Socket={0:X8}, ChannelId={1}, TokenId={2}",
                    (Socket != null)?Socket.Handle:0,
                    (CurrentToken != null)?CurrentToken.ChannelId:0,
                    (CurrentToken != null)?CurrentToken.TokenId:0);

                // close the channel.
                ChannelClosed();
            }

            return(false);
        }
Ejemplo n.º 2
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).ConfigureAwait(false))
                        {
                            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).ConfigureAwait(false);

                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).ConfigureAwait(false);
                }
            }

            return(true);
        }
Ejemplo n.º 3
0
        /// <inheritdoc/>
        public void WriteExtensionObject(string property, ExtensionObject value)
        {
            if (value == null)
            {
                WriteNull(property);
                return;
            }

            var encoding = value.Encoding;
            var typeId   = value.TypeId;
            var body     = value.Body;

            if (body is IEncodeable encodeable)
            {
                if (NodeId.IsNull(typeId))
                {
                    typeId       = encodeable.TypeId;
                    value.TypeId = typeId; // Also fix the extension object
                }
                if (!UseReversibleEncoding)
                {
                    PushObject(property);
                    encodeable.Encode(this);
                    PopObject();
                    return;
                }
                if (UseAdvancedEncoding)
                {
                    encoding = ExtensionObjectEncoding.Json;
                }
                switch (encoding)
                {
                case ExtensionObjectEncoding.Binary:
                    body = encodeable.AsBinary(Context);
                    break;

                case ExtensionObjectEncoding.Json:
                    body = encodeable;     // Encode as json down below.
                    break;

                case ExtensionObjectEncoding.EncodeableObject:
                case ExtensionObjectEncoding.None:
                case ExtensionObjectEncoding.Xml:
                    // Force xml
                    encoding = ExtensionObjectEncoding.Xml;
                    body     = encodeable.AsXmlElement(Context);
                    break;

                default:
                    throw ServiceResultException.Create(
                              StatusCodes.BadEncodingError,
                              "Unexpected encoding encountered while " +
                              $"encoding ExtensionObject:{value.Encoding}");
                }
            }
            else
            {
                if (NodeId.IsNull(typeId) && !UseAdvancedEncoding)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadEncodingError,
                              "Cannot encode extension object without type id.");
                }
            }

            PushObject(property);
            WriteExpandedNodeId("TypeId", typeId);
            if (body != null)
            {
                switch (encoding)
                {
                case ExtensionObjectEncoding.Xml:
                    WriteEncoding("Encoding", encoding);
                    WriteXmlElement("Body", body as XmlElement);
                    break;

                case ExtensionObjectEncoding.Json:
                    WriteEncoding("Encoding", encoding);
                    if (body is EncodeableJToken jt)
                    {
                        // Write encodeable token as json raw
                        body = jt.JToken;
                    }
                    else if (body is IEncodeable o)
                    {
                        PushObject("Body");
                        o.Encode(this);
                        PopObject();
                        break;
                    }
                    PushObject("Body");
                    _writer.WritePropertyName(nameof(EncodeableJToken.JToken));
                    switch (body)
                    {
                    case JToken token:
                        _writer.WriteRaw(token.ToString());
                        break;

                    case string json:
                        _writer.WriteRaw(json);
                        break;

                    case byte[] buffer:
                        _writer.WriteValue(buffer);
                        break;

                    default:
                        throw ServiceResultException.Create(
                                  StatusCodes.BadEncodingError,
                                  "Unexpected value encountered while " +
                                  $"encoding body:{body}");
                    }
                    PopObject();
                    break;

                case ExtensionObjectEncoding.Binary:
                    WriteByteString("Body", body as byte[]);
                    break;
                }
            }
            PopObject();
        }
        /// <summary>
        /// Validates request header and returns a request context.
        /// </summary>
        /// <remarks>
        /// This method verifies that the session id is valid and that it uses secure channel id
        /// associated with current thread. It also verifies that the timestamp is not too
        /// and that the sequence number is not out of order (update requests only).
        /// </remarks>
        public virtual OperationContext ValidateRequest(RequestHeader requestHeader, RequestType requestType)
        {
            if (requestHeader == null)
            {
                throw new ArgumentNullException(nameof(requestHeader));
            }

            Session session = null;

            try
            {
                lock (m_lock)
                {
                    // check for create session request.
                    if (requestType == RequestType.CreateSession || requestType == RequestType.ActivateSession)
                    {
                        return(new OperationContext(requestHeader, requestType));
                    }

                    // find session.
                    if (!m_sessions.TryGetValue(requestHeader.AuthenticationToken, out session))
                    {
                        var handler = m_validateSessionLessRequest;

                        if (handler != null)
                        {
                            var args = new ValidateSessionLessRequestEventArgs(requestHeader.AuthenticationToken, requestType);
                            handler(this, args);

                            if (ServiceResult.IsBad(args.Error))
                            {
                                throw new ServiceResultException(args.Error);
                            }

                            return(new OperationContext(requestHeader, requestType, args.Identity));
                        }

                        throw new ServiceResultException(StatusCodes.BadSessionIdInvalid);
                    }

                    // validate request header.
                    session.ValidateRequest(requestHeader, requestType);

                    // return context.
                    return(new OperationContext(requestHeader, requestType, session));
                }
            }
            catch (Exception e)
            {
                ServiceResultException sre = e as ServiceResultException;

                if (sre != null && sre.StatusCode == StatusCodes.BadSessionNotActivated)
                {
                    if (session != null)
                    {
                        CloseSession(session.Id);
                    }
                }

                throw new ServiceResultException(e, StatusCodes.BadUnexpectedError);
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Reconnects to the server.
        /// </summary>
        private async Task <bool> DoReconnect()
        {
            // try a reconnect.
            if (!m_reconnectFailed)
            {
                try
                {
                    if (m_reverseConnectManager != null)
                    {
                        var connection = await m_reverseConnectManager.WaitForConnection(
                            new Uri(m_session.Endpoint.EndpointUrl),
                            m_session.Endpoint.Server.ApplicationUri
                            ).ConfigureAwait(false);

                        m_session.Reconnect(connection);
                    }
                    else
                    {
                        m_session.Reconnect();
                    }

                    // monitored items should start updating on their own.
                    return(true);
                }
                catch (Exception exception)
                {
                    // recreate the session if it has been closed.
                    ServiceResultException sre = exception as ServiceResultException;

                    // check if the server endpoint could not be reached.
                    if ((sre != null &&
                         (sre.StatusCode == StatusCodes.BadTcpInternalError ||
                          sre.StatusCode == StatusCodes.BadCommunicationError ||
                          sre.StatusCode == StatusCodes.BadNotConnected ||
                          sre.StatusCode == StatusCodes.BadTimeout)))
                    {
                        // check if reconnecting is still an option.
                        if (m_session.LastKeepAliveTime.AddMilliseconds(m_session.SessionTimeout) > DateTime.UtcNow)
                        {
                            Utils.Trace("Calling OnReconnectSession in {0} ms.", m_reconnectPeriod);
                            return(false);
                        }
                    }

                    m_reconnectFailed = true;
                }
            }

            // re-create the session.
            try
            {
                Session session;
                if (m_reverseConnectManager != null)
                {
                    var connection = await m_reverseConnectManager.WaitForConnection(
                        new Uri(m_session.Endpoint.EndpointUrl),
                        m_session.Endpoint.Server.ApplicationUri
                        ).ConfigureAwait(false);

                    session = Session.Recreate(m_session, connection);
                }
                else
                {
                    session = Session.Recreate(m_session);
                }
                m_session.Close();
                m_session = session;
                return(true);
            }
            catch (Exception exception)
            {
                Utils.Trace("Could not reconnect the Session. {0}", exception.Message);
                return(false);
            }
        }
Ejemplo n.º 6
0
        /// <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;
                    }
                    m_readState = ReadState.NotConnected;
                    return;
                }

                socket = m_socket;

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

            BufferManager.LockBuffer(m_receiveBuffer);

            var args = new SocketAsyncEventArgs();

            try
            {
                m_readState = ReadState.Receive;
                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());
                    }
                    // set state to inner complete
                    m_readState = ReadState.ReadComplete;
                    m_readComplete(null, args);
                }
            }
            catch (ServiceResultException)
            {
                args?.Dispose();
                BufferManager.UnlockBuffer(m_receiveBuffer);
                throw;
            }
            catch (Exception ex)
            {
                args?.Dispose();
                BufferManager.UnlockBuffer(m_receiveBuffer);
                throw ServiceResultException.Create(StatusCodes.BadTcpInternalError, ex, "BeginReceive failed.");
            }
        }
Ejemplo n.º 7
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);
        }
Ejemplo n.º 8
0
        /// <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));

                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));
                        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);
        }
Ejemplo n.º 9
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);
            }
        }
Ejemplo n.º 10
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);
            }
        }
Ejemplo n.º 11
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);
        }
Ejemplo n.º 12
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>
        /// Display the exception in the dialog.
        /// </summary>
        public void ShowDialog(string caption, Exception e)
        {
            Text.Text = caption;

            StringBuilder buffer = new StringBuilder();

            buffer.Append("<html><body style='margin:0'>");

            while (e != null)
            {
                string message = e.Message;

                ServiceResultException exception = e as ServiceResultException;

                if (exception != null)
                {
                    message = exception.ToLongString();
                }

                message = ReplaceSpecialCharacters(message);

                if (exception != null)
                {
                    buffer.Append("<p>");
                    buffer.Append("<font style='font:9pt/12pt verdana;color:black'>");
                    buffer.Append(message);
                    buffer.Append("</font>");
                    buffer.Append("</p>");
                }
                else
                {
                    buffer.Append("<font style='font:9pt/12pt verdana;color:red'><b>");
                    buffer.Append(message);
                    buffer.Append("</b></font><br>");
                }

                message = e.StackTrace;

                if (!String.IsNullOrEmpty(message))
                {
                    message = ReplaceSpecialCharacters(message);

                    buffer.Append("<p>");
                    buffer.Append("<font style='font:9pt/12pt verdana;color:black'>");
                    buffer.Append(message);
                    buffer.Append("</font>");
                    buffer.Append("</p>");
                }

                e = e.InnerException;
            }

            buffer.Append("</body></html>");

            ExceptionBrowser.NavigateToString(buffer.ToString());

            Popup myPopup = new Popup();

            myPopup.Child  = this;
            myPopup.IsOpen = true;
        }
        private async Task ReceiveResponsesAsync(CancellationToken token = default(CancellationToken))
        {
            while (!token.IsCancellationRequested)
            {
                try
                {
                    var response = await this.ReceiveResponseAsync(token).ConfigureAwait(false);
                    if (response == null)
                    {
                        // Null response indicates socket closed. This is expected when closing secure channel.
                        if (this.State == CommunicationState.Closing)
                        {
                            return;
                        }

                        throw new ServiceResultException(StatusCodes.BadServerNotConnected);
                    }

                    var header = response.ResponseHeader;
                    TaskCompletionSource<IServiceResponse> tcs;
                    if (this.pendingCompletions.TryRemove(header.RequestHandle, out tcs))
                    {
                        if (StatusCode.IsBad(header.ServiceResult))
                        {
                            var ex = new ServiceResultException(new ServiceResult(header.ServiceResult, header.ServiceDiagnostics, header.StringTable));
                            Log.Warn($"Received {response.GetType().Name} Handle: {response.ResponseHeader.RequestHandle} Code: {header.ServiceResult} - {ex.Message}");
                            tcs.TrySetException(ex);
                        }
                        else
                        {
                            Log.Trace($"Received {response.GetType().Name} Handle: {response.ResponseHeader.RequestHandle}");
                            tcs.TrySetResult(response);
                        }
                    }

                    // check if time to renew token
                    if (this.State == CommunicationState.Opened && DateTime.UtcNow > this.tokenRenewalTime)
                    {
                        this.tokenRenewalTime = this.tokenRenewalTime.AddMilliseconds(60000);
                        var task = Task.Run(() => this.OnRenewAsync(token));
                    }
                }
                catch (Exception ex)
                {
                    if (!token.IsCancellationRequested)
                    {
                        await this.FaultAsync(ex).ConfigureAwait(false);
                        await this.AbortAsync().ConfigureAwait(false);
                    }
                }
            }
        }
Ejemplo n.º 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);
            }
        }
        /// <summary>
        /// Translates an exception.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="e">The ServiceResultException e.</param>
        /// <returns>Returns an exception thrown when a UA defined error occurs, the return type is <seealso cref="ServiceResultException"/>.</returns>
        protected virtual ServiceResultException TranslateException(OperationContext context, ServiceResultException e)
        {
            IList<string> preferredLocales = null;

            if (context != null && context.Session != null)
            {
                preferredLocales = context.Session.PreferredLocales;
            }

            return TranslateException(context.DiagnosticsMask, preferredLocales, e);
        }
Ejemplo n.º 17
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];
                IBuffer buffer = CryptographicBuffer.GenerateRandom((uint)m_minNonceLength);
                CryptographicBuffer.CopyToByteArray(buffer, out 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);
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Reconnects to the server.
        /// </summary>
        private bool DoReconnect()
        {
            // try a reconnect.
            if (!m_reconnectFailed)
            {
                try
                {
                    m_session.Reconnect();

                    // monitored items should start updating on their own.
                    return(true);
                }
                catch (Exception exception)
                {
                    bool recreateNow = false;

                    // recreate the session if it has been closed or the nonce is wrong.
                    ServiceResultException sre = exception as ServiceResultException;

                    if (sre != null)
                    {
                        switch (sre.StatusCode)
                        {
                        case StatusCodes.BadSessionClosed:
                        case StatusCodes.BadApplicationSignatureInvalid:
                        {
                            recreateNow = true;
                            break;
                        }

                        default:
                        {
                            Utils.Trace((int)Utils.TraceMasks.Error, "Unexpected RECONNECT error code. {0}", sre.StatusCode);
                            break;
                        }
                        }
                    }

                    m_reconnectFailed = true;

                    // try a reconnect again after a delay.
                    if (!recreateNow)
                    {
                        Utils.Trace("Reconnect failed. {0}", exception.Message);
                        return(false);
                    }
                }
            }

            // re-create the session.
            try
            {
                Session session = Session.Recreate(m_session);
                m_session.Close();
                m_session = session;
                return(true);
            }
            catch (Exception exception)
            {
                Utils.Trace("Unexpected re-creating a Session with the UA Server. {0}", exception.Message);
                return(false);
            }
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Creates a session with the endpoint.
        /// </summary>
        public async Task <Session> Connect(ConfiguredEndpoint endpoint)
        {
            if (endpoint == null)
            {
                throw new ArgumentNullException("endpoint");
            }

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

            if (endpoint == null)
            {
                return(null);
            }

            m_endpoint = endpoint;

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

            X509Certificate2 clientCertificate = null;

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

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

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

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

            try
            {
                // create the session.
                Session session = new Session(channel, m_configuration, endpoint, null);
                session.ReturnDiagnostics = DiagnosticsMasks.All;

                SessionOpenDlg sessiondlg = new SessionOpenDlg();
                session = await sessiondlg.ShowDialog(session, PreferredLocales);

                if (session != null)
                {
                    // session now owns the channel.
                    channel = null;
                    // add session to tree.
                    AddNode(session);

                    return(session);
                }
            }
            finally
            {
                // ensure the channel is closed on error.
                if (channel != null)
                {
                    channel.Close();
                    channel = null;
                }
            }

            return(null);
        }
        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.Trace("Token #{0} activated forced.", 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,
                          "TokenId is not known. ChanneId={0}, TokenId={1}, CurrentTokenId={2}, PreviousTokenId={3}",
                          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, "Token #{0} has expired. Lifetime={1:HH:mm:ss.fff}", 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.Trace("Could not verify signature on message.");
                    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));
        }
Ejemplo n.º 21
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);
                }
            }
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Writes the contents of an Variant to the stream.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="valueRank"></param>
        /// <param name="builtInType"></param>
        private void WriteVariantContents(object value, int valueRank,
                                          BuiltInType builtInType)
        {
            // write scalar.
            if (valueRank < 0)
            {
                switch (builtInType)
                {
                case BuiltInType.Null:
                    WriteNull(null);
                    return;

                case BuiltInType.Boolean:
                    WriteBoolean(null, (bool)value);
                    return;

                case BuiltInType.SByte:
                    WriteSByte(null, (sbyte)value);
                    return;

                case BuiltInType.Byte:
                    WriteByte(null, (byte)value);
                    return;

                case BuiltInType.Int16:
                    WriteInt16(null, (short)value);
                    return;

                case BuiltInType.UInt16:
                    WriteUInt16(null, (ushort)value);
                    return;

                case BuiltInType.Int32:
                    WriteInt32(null, (int)value);
                    return;

                case BuiltInType.UInt32:
                    WriteUInt32(null, (uint)value);
                    return;

                case BuiltInType.Int64:
                    WriteInt64(null, (long)value);
                    return;

                case BuiltInType.UInt64:
                    WriteUInt64(null, (ulong)value);
                    return;

                case BuiltInType.Float:
                    WriteFloat(null, (float)value);
                    return;

                case BuiltInType.Double:
                    WriteDouble(null, (double)value);
                    return;

                case BuiltInType.String:
                    WriteString(null, (string)value);
                    return;

                case BuiltInType.DateTime:
                    WriteDateTime(null, (DateTime)value);
                    return;

                case BuiltInType.Guid:
                    WriteGuid(null, (Uuid)value);
                    return;

                case BuiltInType.ByteString:
                    WriteByteString(null, (byte[])value);
                    return;

                case BuiltInType.XmlElement:
                    WriteXmlElement(null, (XmlElement)value);
                    return;

                case BuiltInType.NodeId:
                    WriteNodeId(null, (NodeId)value);
                    return;

                case BuiltInType.ExpandedNodeId:
                    WriteExpandedNodeId(null, (ExpandedNodeId)value);
                    return;

                case BuiltInType.StatusCode:
                    WriteStatusCode(null, (StatusCode)value);
                    return;

                case BuiltInType.QualifiedName:
                    WriteQualifiedName(null, (QualifiedName)value);
                    return;

                case BuiltInType.LocalizedText:
                    WriteLocalizedText(null, (LocalizedText)value);
                    return;

                case BuiltInType.ExtensionObject:
                    WriteExtensionObject(null, (ExtensionObject)value);
                    return;

                case BuiltInType.DataValue:
                    WriteDataValue(null, (DataValue)value);
                    return;

                case BuiltInType.Enumeration:
                    WriteInt32(null, (int)value);
                    return;

                case BuiltInType.Number:
                case BuiltInType.Integer:
                case BuiltInType.UInteger:
                case BuiltInType.Variant:
                    throw ServiceResultException.Create(StatusCodes.BadEncodingError,
                                                        "Unexpected type encountered while encoding variant " +
                                                        value.GetType());
                }
            }

            // write array.
            else if (valueRank <= 1)
            {
                switch (builtInType)
                {
                case BuiltInType.Null:
                    WriteNull(null);
                    return;

                case BuiltInType.Boolean:
                    WriteBooleanArray(null, (bool[])value);
                    return;

                case BuiltInType.SByte:
                    WriteSByteArray(null, (sbyte[])value);
                    return;

                case BuiltInType.Byte:
                    WriteByteArray(null, (byte[])value);
                    return;

                case BuiltInType.Int16:
                    WriteInt16Array(null, (short[])value);
                    return;

                case BuiltInType.UInt16:
                    WriteUInt16Array(null, (ushort[])value);
                    return;

                case BuiltInType.Int32:
                    WriteInt32Array(null, (int[])value);
                    return;

                case BuiltInType.UInt32:
                    WriteUInt32Array(null, (uint[])value);
                    return;

                case BuiltInType.Int64:
                    WriteInt64Array(null, (long[])value);
                    return;

                case BuiltInType.UInt64:
                    WriteUInt64Array(null, (ulong[])value);
                    return;

                case BuiltInType.Float:
                    WriteFloatArray(null, (float[])value);
                    return;

                case BuiltInType.Double:
                    WriteDoubleArray(null, (double[])value);
                    return;

                case BuiltInType.String:
                    WriteStringArray(null, (string[])value);
                    return;

                case BuiltInType.DateTime:
                    WriteDateTimeArray(null, (DateTime[])value);
                    return;

                case BuiltInType.Guid:
                    WriteGuidArray(null, (Uuid[])value);
                    return;

                case BuiltInType.ByteString:
                    WriteByteStringArray(null, (byte[][])value);
                    return;

                case BuiltInType.XmlElement:
                    WriteXmlElementArray(null, (XmlElement[])value);
                    return;

                case BuiltInType.NodeId:
                    WriteNodeIdArray(null, (NodeId[])value);
                    return;

                case BuiltInType.ExpandedNodeId:
                    WriteExpandedNodeIdArray(null, (ExpandedNodeId[])value);
                    return;

                case BuiltInType.StatusCode:
                    WriteStatusCodeArray(null, (StatusCode[])value);
                    return;

                case BuiltInType.QualifiedName:
                    WriteQualifiedNameArray(null, (QualifiedName[])value);
                    return;

                case BuiltInType.LocalizedText:
                    WriteLocalizedTextArray(null, (LocalizedText[])value);
                    return;

                case BuiltInType.ExtensionObject:
                    WriteExtensionObjectArray(null, (ExtensionObject[])value);
                    return;

                case BuiltInType.DataValue:
                    WriteDataValueArray(null, (DataValue[])value);
                    return;

                case BuiltInType.Enumeration:
                    var enums  = value as Enum[];
                    var values = new string[enums.Length];

                    for (var index = 0; index < enums.Length; index++)
                    {
                        var text = enums[index].ToString();
                        text         += "_";
                        text         += ((int)(object)enums[index]).ToString(CultureInfo.InvariantCulture);
                        values[index] = text;
                    }

                    WriteStringArray(null, values);
                    return;

                case BuiltInType.Number:
                case BuiltInType.UInteger:
                case BuiltInType.Integer:
                case BuiltInType.Variant:
                    if (value is Variant[] variants)
                    {
                        WriteVariantArray(null, variants);
                        return;
                    }
                    if (value is object[] objects)
                    {
                        WriteObjectArray(null, objects);
                        return;
                    }
                    throw ServiceResultException.Create(StatusCodes.BadEncodingError,
                                                        "Unexpected type encountered while encoding an array" +
                                                        $" of Variants:{value.GetType()}");
                }
            }

            else
            {
                if (value == null)
                {
                    WriteNull(null);
                    return;
                }
                if (value is Matrix matrix)
                {
                    var index = 0;
                    WriteMatrix(matrix, 0, ref index, builtInType);
                    return;
                }
            }
            // oops - should never happen.
            throw new ServiceResultException(StatusCodes.BadEncodingError,
                                             $"Type '{value.GetType().FullName}' is not allowed in an Variant.");
        }
Ejemplo n.º 23
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");
                }
            }
        }
Ejemplo n.º 24
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.BadSessionIdInvalid);
                }

                // check if session timeout has expired.
                if (session.HasExpired)
                {
                    // raise audit event for session closed because of timeout
                    m_server.ReportAuditCloseSessionEvent(null, session, "Session/Timeout");

                    m_server.CloseSession(null, session.Id, false);

                    throw new ServiceResultException(StatusCodes.BadSessionClosed);
                }

                // create new server nonce.
                serverNonce = Utils.Nonce.CreateNonce((uint)m_minNonceLength);

                // 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, context.ChannelContext.EndpointDescription);
                        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 = newIdentity != null ? new UserIdentity(newIdentity) : new UserIdentity();
                }

                // 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);
        }
Ejemplo n.º 25
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;
            }
        }
Ejemplo n.º 26
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));
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Creates a session with the server.
        /// </summary>
        /// <param name="state">The state.</param>
        private void OnReconnectSession(object state)
        {
            // get the CLSID of the COM server.
            Session session = state as Session;

            if (session == null)
            {
                return;
            }

            // check if nothing to do.
            lock (m_lock)
            {
                if (!m_running || !Object.ReferenceEquals(m_session, session))
                {
                    return;
                }

                // stop the reconnect timer.
                if (m_reconnectTimer != null)
                {
                    m_reconnectTimer.Dispose();
                    m_reconnectTimer = null;
                }
            }

            // reconnect the session.
            try
            {
                session.Reconnect();

                lock (m_lock)
                {
                    if (!m_running || !Object.ReferenceEquals(m_session, session))
                    {
                        session.Dispose();
                        return;
                    }
                }

                OnSessionReconected();
            }
            catch (Exception e)
            {
                Utils.Trace("Unexpected reconnecting a Session with the UA Server. {0}", e.Message);

                // schedule a reconnect.
                lock (m_lock)
                {
                    // check if session has been replaced.
                    if (!m_running || !Object.ReferenceEquals(m_session, session))
                    {
                        session.Dispose();
                        return;
                    }

                    // check if the session has been closed.
                    ServiceResultException sre = e as ServiceResultException;

                    if (sre == null || sre.StatusCode != StatusCodes.BadSessionClosed)
                    {
                        m_session = null;
                        session.Dispose();
                        OnSessionRemoved();
                        ThreadPool.QueueUserWorkItem(OnCreateSession, null);
                        Utils.Trace("Calling OnCreateSession NOW.");
                        return;
                    }

                    // check if reconnecting is still an option.
                    if (m_lastKeepAliveTime.AddMilliseconds(session.SessionTimeout) > DateTime.UtcNow)
                    {
                        m_reconnectTimer = new Timer(OnReconnectSession, session, 20000, Timeout.Infinite);
                        Utils.Trace("Calling OnReconnectSession in 20000ms.");
                        OnReconnectInProgress(20);
                        return;
                    }

                    // give up and re-create the session.
                    m_session = null;
                    session.Dispose();
                    OnSessionRemoved();
                    m_reconnectTimer = new Timer(OnCreateSession, null, 20000, Timeout.Infinite);
                    Utils.Trace("Calling OnCreateSession in 20000ms.");
                    OnReconnectInProgress(20);
                }
            }
        }
Ejemplo n.º 28
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, signare and trust list checks pass, we return the other specific validation errors instead of BadSecurityChecksFailed

                if (innerException != null && (
                        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.BadCertificateRevoked ||
                        innerException.StatusCode == StatusCodes.BadCertificateIssuerRevoked))
                {
                    ForceChannelFault(innerException, innerException.StatusCode, e.Message);
                    return(false);
                }
                else
                {
                    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.
                TcpChannelToken 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.
                        m_listener.ReconnectToExistingChannel(
                            Socket,
                            requestId,
                            sequenceNumber,
                            channelId,
                            ClientCertificate,
                            token,
                            request);

                        Utils.Trace(
                            "TCPSERVERCHANNEL ReconnectToExistingChannel Socket={0:X8}, ChannelId={1}, TokenId={2}",
                            (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 rewew 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(
                        g_ImplementationString,
                        this.m_listener.EndpointUrl.ToString(),
                        Utils.Format("{0}", this.ChannelId),
                        this.EndpointDescription,
                        this.ClientCertificate,
                        this.ServerCertificate,
                        BinaryEncodingSupport.Required);
                }
                else
                {
                    Opc.Ua.Security.Audit.SecureChannelRenewed(
                        g_ImplementationString,
                        Utils.Format("{0}", this.ChannelId));
                }

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

                State = TcpChannelState.Open;

                // send the response.
                SendOpenSecureChannelResponse(requestId, token, request);
                return(false);
            }
            catch (Exception e)
            {
                SendServiceFault(requestId, ServiceResult.Create(e, StatusCodes.BadTcpInternalError, "Unexpected error processing OpenSecureChannel request."));
                return(false);
            }
            finally
            {
                if (chunksToProcess != null)
                {
                    chunksToProcess.Release(BufferManager, "ProcessOpenSecureChannelRequest");
                }
            }
        }
Ejemplo n.º 29
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);
            }
        }
        /// <summary>
        /// Creates the response header.
        /// </summary>
        /// <param name="requestHeader">The object that contains description for the RequestHeader DataType.</param>
        /// <param name="exception">The exception used to create DiagnosticInfo assigned to the ServiceDiagnostics.</param>
        /// <returns>Returns a description for the ResponseHeader DataType. </returns>
        protected ResponseHeader CreateResponse(RequestHeader requestHeader, ServiceResultException exception)
        {
            ResponseHeader responseHeader = new ResponseHeader();

            responseHeader.ServiceResult = exception.StatusCode;

            responseHeader.Timestamp = DateTime.UtcNow;
            responseHeader.RequestHandle = requestHeader.RequestHandle;

            StringTable stringTable = new StringTable();
            responseHeader.ServiceDiagnostics = new DiagnosticInfo(exception, (DiagnosticsMasks)requestHeader.ReturnDiagnostics, true, stringTable);
            responseHeader.StringTable = stringTable.ToArray();

            return responseHeader;
        }
Ejemplo n.º 31
0
        protected void ReadAsymmetricMessageHeader(
            BinaryDecoder decoder,
            X509Certificate2 receiverCertificate,
            out uint secureChannelId,
            out X509Certificate2Collection senderCertificateChain,
            out string securityPolicyUri)
        {
            senderCertificateChain = null;

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

            // decode security header.
            byte[] certificateData = null;
            byte[] thumbprintData  = null;

            try
            {
                secureChannelId   = decoder.ReadUInt32(null);
                securityPolicyUri = decoder.ReadString(null, TcpMessageLimits.MaxSecurityPolicyUriSize);
                certificateData   = decoder.ReadByteString(null, TcpMessageLimits.MaxCertificateSize);
                thumbprintData    = decoder.ReadByteString(null, TcpMessageLimits.CertificateThumbprintSize);
            }
            catch (Exception e)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadSecurityChecksFailed,
                          e,
                          "The asymmetric security header could not be parsed.");
            }

            // verify sender certificate chain.
            if (certificateData != null && certificateData.Length > 0)
            {
                senderCertificateChain = Utils.ParseCertificateChainBlob(certificateData);

                try
                {
                    string thumbprint = senderCertificateChain[0].Thumbprint;

                    if (thumbprint == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "Invalid certificate thumbprint.");
                    }
                }
                catch (Exception e)
                {
                    throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, e, "The sender's certificate could not be parsed.");
                }
            }
            else
            {
                if (securityPolicyUri != SecurityPolicies.None)
                {
                    throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The sender's certificate was not specified.");
                }
            }

            // verify receiver thumbprint.
            if (thumbprintData != null && thumbprintData.Length > 0)
            {
                if (receiverCertificate.Thumbprint.ToUpperInvariant() != GetThumbprintString(thumbprintData))
                {
                    throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The receiver's certificate thumbprint is not valid.");
                }
            }
            else
            {
                if (securityPolicyUri != SecurityPolicies.None)
                {
                    throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The receiver's certificate thumbprint was not specified.");
                }
            }
        }
Ejemplo n.º 32
0
        /// <summary>
        /// Handles a certificate validation error.
        /// </summary>
        private bool HandleValidationError(X509Certificate2 certificate, ServiceResultException e)
        {
            StringBuilder buffer = new StringBuilder();

            switch (e.StatusCode)
            {
                case StatusCodes.BadCertificateIssuerRevocationUnknown:
                {
                    buffer.AppendFormat("Could not determine whether the issuing certificate was revoked.");
                    buffer.Append("\r\n");
                    buffer.Append("Would you still like to accept the certificate?\r\n");
                    break;
                }

                case StatusCodes.BadCertificateIssuerTimeInvalid:
                {
                    buffer.AppendFormat("The issuing certificate has expired or is not yet valid.");
                    buffer.Append("\r\n");
                    buffer.Append("Would you still like to accept the certificate?\r\n");
                    break;
                }

                case StatusCodes.BadCertificateRevocationUnknown:
                {
                    buffer.AppendFormat("Could not determine whether the certificate was revoked by the Certificate Authority.");
                    buffer.Append("\r\n");
                    buffer.Append("Would you still like to accept the certificate?\r\n");
                    break;
                }

                case StatusCodes.BadCertificateTimeInvalid:
                {
                    buffer.AppendFormat("The certificate has expired or is not yet valid.");
                    buffer.Append("\r\n");
                    buffer.Append("Would you still like to accept the certificate?\r\n");
                    buffer.Append("\r\n");
                    buffer.Append("Certificate = ");
                    buffer.Append(certificate.Subject);
                    buffer.Append("\r\n");
                    buffer.Append("Valid From = ");
                    buffer.Append(certificate.NotBefore.ToLocalTime());
                    buffer.Append("\r\n");
                    buffer.Append("Valid To = ");
                    buffer.Append(certificate.NotBefore.ToLocalTime());
                    break;
                }

                case StatusCodes.BadCertificateUntrusted:
                {
                    if (Utils.CompareDistinguishedName(certificate.Issuer, certificate.Subject))
                    {
                        return true;
                    }

                    buffer.Append("This certificates was issued by an unknown Certificate Authority.");
                    buffer.Append("This means it could have been altered and there is no way to detect changes.");
                    buffer.Append("You should only accept it if you are absolutely certain the certificate has come via a secure channel from a legimate source.");
                    buffer.Append("\r\n");
                    buffer.Append("\r\n");
                    buffer.Append("Would you still like to accept the certificate?\r\n");
                    buffer.Append("\r\n");
                    buffer.Append("Certificate = ");
                    buffer.Append(certificate.Subject);
                    buffer.Append("\r\n");
                    buffer.Append("Certificate Authority = ");
                    buffer.Append(certificate.Issuer);
                    break;
                }

                default:
                {
                    buffer.Append("An error that cannot be ignored occurred during validation.\r\n");
                    buffer.Append("\r\n");
                    buffer.Append("Certificate = ");
                    buffer.Append(certificate.Subject);
                    buffer.Append("\r\n");
                    buffer.Append("ErrorCode = ");
                    buffer.Append(StatusCodes.GetBrowseName(e.StatusCode));
                    buffer.Append("\r\n");
                    buffer.Append("Message = ");
                    buffer.Append(e.Message);

                    new YesNoDlg().ShowDialog(buffer.ToString(), "Certificate Validation Error");
                    return false;
                }
            }

            DialogResult result = new YesNoDlg().ShowDialog(buffer.ToString(), "Certificate Validation Error");

            if (result != DialogResult.Yes)
            {
                return false;
            }

            return true;
        }
Ejemplo n.º 33
0
        /// <summary>
        /// Processes an OpenSecureChannel request message.
        /// </summary>
        protected ArraySegment <byte> ReadAsymmetricMessage(
            ArraySegment <byte> buffer,
            X509Certificate2 receiverCertificate,
            out uint channelId,
            out X509Certificate2 senderCertificate,
            out uint requestId,
            out uint sequenceNumber)
        {
            BinaryDecoder decoder = new BinaryDecoder(buffer.Array, buffer.Offset, buffer.Count, Quotas.MessageContext);

            string securityPolicyUri = null;
            X509Certificate2Collection senderCertificateChain;

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

            if (senderCertificateChain != null && senderCertificateChain.Count > 0)
            {
                senderCertificate = senderCertificateChain[0];
            }
            else
            {
                senderCertificate = null;
            }

            // validate the sender certificate.
            if (senderCertificate != null && Quotas.CertificateValidator != null && securityPolicyUri != SecurityPolicies.None)
            {
                CertificateValidator certificateValidator = Quotas.CertificateValidator as CertificateValidator;

                if (certificateValidator != null)
                {
                    certificateValidator.Validate(senderCertificateChain);
                }
                else
                {
                    Quotas.CertificateValidator.Validate(senderCertificate);
                }
            }

            // check if this is the first open secure channel request.
            if (!m_uninitialized)
            {
                if (securityPolicyUri != m_securityPolicyUri)
                {
                    throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "Cannot change the security policy after creating the channnel.");
                }
            }
            else
            {
                // find a matching endpoint description.
                if (m_endpoints != null)
                {
                    foreach (EndpointDescription endpoint in m_endpoints)
                    {
                        // There may be multiple endpoints with the same securityPolicyUri.
                        // Just choose the first one that matches. This choice will be re-examined
                        // When the OpenSecureChannel request body is processed.
                        if (endpoint.SecurityPolicyUri == securityPolicyUri || (securityPolicyUri == SecurityPolicies.None && endpoint.SecurityMode == MessageSecurityMode.None))
                        {
                            m_securityMode      = endpoint.SecurityMode;
                            m_securityPolicyUri = securityPolicyUri;
                            m_discoveryOnly     = false;
                            m_uninitialized     = false;
                            m_selectedEndpoint  = endpoint;

                            // recalculate the key sizes.
                            CalculateSymmetricKeySizes();
                            break;
                        }
                    }
                }

                // allow a discovery only channel with no security if policy not suppported
                if (m_uninitialized)
                {
                    if (securityPolicyUri != SecurityPolicies.None)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "The security policy is not supported.");
                    }

                    m_securityMode      = MessageSecurityMode.None;
                    m_securityPolicyUri = SecurityPolicies.None;
                    m_discoveryOnly     = true;
                    m_uninitialized     = false;
                    m_selectedEndpoint  = null;
                }
            }

            int headerSize = decoder.Position;

            // decrypt the body.
            ArraySegment <byte> plainText = Decrypt(
                new ArraySegment <byte>(buffer.Array, buffer.Offset + headerSize, buffer.Count - headerSize),
                new ArraySegment <byte>(buffer.Array, buffer.Offset, headerSize),
                receiverCertificate);

            // extract signature.
            int signatureSize = GetAsymmetricSignatureSize(senderCertificate);

            byte[] signature = new byte[signatureSize];

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

            // verify the signature.
            ArraySegment <byte> dataToVerify = new ArraySegment <byte>(plainText.Array, plainText.Offset, plainText.Count - signatureSize);

            if (!Verify(dataToVerify, signature, senderCertificate))
            {
                Utils.Trace("Could not verify signature on message.");
                throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the signature on the message.");
            }

            // verify padding.
            int paddingCount = 0;

            if (SecurityMode != MessageSecurityMode.None)
            {
                int paddingEnd = -1;
                if (CertificateFactory.GetRSAPublicKeySize(receiverCertificate) > TcpMessageLimits.KeySizeExtraPadding)
                {
                    paddingEnd   = plainText.Offset + plainText.Count - signatureSize - 1;
                    paddingCount = plainText.Array[paddingEnd - 1] + plainText.Array[paddingEnd] * 256;

                    //parse until paddingStart-1; the last one is actually the extrapaddingsize
                    for (int ii = paddingEnd - paddingCount; ii < paddingEnd; ii++)
                    {
                        if (plainText.Array[ii] != plainText.Array[paddingEnd - 1])
                        {
                            throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the padding in the message.");
                        }
                    }
                }
                else
                {
                    paddingEnd   = plainText.Offset + plainText.Count - signatureSize - 1;
                    paddingCount = plainText.Array[paddingEnd];

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

                paddingCount++;
            }

            // decode message.
            decoder = new BinaryDecoder(
                plainText.Array,
                plainText.Offset + headerSize,
                plainText.Count - headerSize,
                Quotas.MessageContext);

            sequenceNumber = decoder.ReadUInt32(null);
            requestId      = decoder.ReadUInt32(null);

            headerSize += decoder.Position;
            decoder.Close();

            Utils.Trace("Security Policy: {0}", SecurityPolicyUri);
            Utils.Trace("Sender Certificate: {0}", (senderCertificate != null) ? senderCertificate.Subject : "(none)");

            // return the body.
            return(new ArraySegment <byte>(
                       plainText.Array,
                       plainText.Offset + headerSize,
                       plainText.Count - headerSize - signatureSize - paddingCount));
        }
        /// <summary>
        /// Translates an exception.
        /// </summary>
        /// <param name="diagnosticsMasks">The fields to return.</param>
        /// <param name="preferredLocales">The preferred locales.</param>
        /// <param name="e">The ServiceResultException e.</param>
        /// <returns>Returns an exception thrown when a UA defined error occurs, the return type is <seealso cref="ServiceResultException"/>.</returns>
        protected virtual ServiceResultException TranslateException(DiagnosticsMasks diagnosticsMasks, IList<string> preferredLocales, ServiceResultException e)
        {
            if (e == null)
            {
                return null;
            }
            
            // check if inner result required.
            ServiceResult innerResult = null;

            if ((diagnosticsMasks & (DiagnosticsMasks.ServiceInnerDiagnostics | DiagnosticsMasks.ServiceInnerStatusCode)) != 0)
            {
                innerResult = e.InnerResult;
            }

            // check if translated text required.
            LocalizedText translatedText = null;

            if ((diagnosticsMasks & DiagnosticsMasks.ServiceLocalizedText) != 0)
            {
                translatedText = e.LocalizedText;
            }

            // create new result object.
            ServiceResult result = new ServiceResult(
                e.StatusCode,
                e.SymbolicId,
                e.NamespaceUri,
                translatedText,
                e.AdditionalInfo,
                innerResult);

            // translate result.
            result = m_serverInternal.ResourceManager.Translate(preferredLocales, result);
            return new ServiceResultException(result);
        }
Ejemplo n.º 35
0
        /// <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);
            }
        }