/// <summary> /// Creates a new certificate for application. /// </summary> /// <param name="application">The application.</param> private static async Task <X509Certificate2> CreateCertificateForApplication(InstalledApplication application) { // build list of domains. List <string> domains = new List <string>(); if (application.BaseAddresses != null) { foreach (string baseAddress in application.BaseAddresses) { Uri uri = Utils.ParseUri(baseAddress); if (uri != null) { string domain = uri.DnsSafeHost; if (String.Compare(domain, "localhost", StringComparison.OrdinalIgnoreCase) == 0) { domain = Utils.GetHostName(); } if (!Utils.FindStringIgnoreCase(domains, domain)) { domains.Add(domain); } } } } // must at least of the localhost. if (domains.Count == 0) { domains.Add(Utils.GetHostName()); } // create the certificate. X509Certificate2 certificate = await Opc.Ua.CertificateFactory.CreateCertificate( application.ApplicationCertificate.StoreType, application.ApplicationCertificate.StorePath, application.ApplicationUri, application.ApplicationName, Utils.Format("CN={0}/DC={1}", application.ApplicationName, domains[0]), domains, 1024, 300); CertificateIdentifier applicationCertificate = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(application.ApplicationCertificate); return(await applicationCertificate.LoadPrivateKey(null)); }
/// <summary> /// Uninstalls a UA application. /// </summary> public static async Task UninstallApplication(InstalledApplication application) { // validate the executable file. string executableFile = Utils.GetAbsoluteFilePath(application.ExecutableFile, true, true, false); // get the default application name from the executable file. FileInfo executableFileInfo = new FileInfo(executableFile); string applicationName = executableFileInfo.Name.Substring(0, executableFileInfo.Name.Length - 4); // choose a default configuration file. if (String.IsNullOrEmpty(application.ConfigurationFile)) { application.ConfigurationFile = Utils.Format( "{0}\\{1}.Config.xml", executableFileInfo.DirectoryName, applicationName); } // validate the configuration file. string configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, false, false); if (configurationFile != null) { // load the current configuration. Opc.Ua.Security.SecuredApplication security = new Opc.Ua.Security.SecurityConfigurationManager().ReadConfiguration(configurationFile); // delete the application certificates. if (application.DeleteCertificatesOnUninstall) { CertificateIdentifier id = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(security.ApplicationCertificate); // delete public key from trusted peers certificate store. try { CertificateStoreIdentifier certificateStore = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(security.TrustedCertificateStore); using (ICertificateStore store = certificateStore.OpenStore()) { X509Certificate2Collection peerCertificates = await store.FindByThumbprint(id.Thumbprint); if (peerCertificates.Count > 0) { await store.Delete(peerCertificates[0].Thumbprint); } } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } // delete private key from application certificate store. try { using (ICertificateStore store = id.OpenStore()) { await store.Delete(id.Thumbprint); } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } // permentently delete any UA defined stores if they are now empty. try { WindowsCertificateStore store = new WindowsCertificateStore(); await store.Open("LocalMachine\\UA Applications"); X509Certificate2Collection collection = await store.Enumerate(); if (collection.Count == 0) { store.PermanentlyDeleteStore(); } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } } // remove the permissions for the HTTP endpoints used by the application. if (application.BaseAddresses != null && application.BaseAddresses.Count > 0) { List <ApplicationAccessRule> noRules = new List <ApplicationAccessRule>(); for (int ii = 0; ii < application.BaseAddresses.Count; ii++) { Uri url = Utils.ParseUri(application.BaseAddresses[ii]); if (url != null) { try { HttpAccessRule.SetAccessRules(url, noRules, true); Utils.Trace("Removed HTTP access rules for URL: {0}", url); } catch (Exception e) { Utils.Trace("Could not remove HTTP access rules for URL: {0}. Error={1}", url, e.Message); } } } } } }
/// <summary> /// Installs a UA application. /// </summary> public static async Task InstallApplication( InstalledApplication application, bool autostart, bool configureFirewall) { // validate the executable file. string executableFile = Utils.GetAbsoluteFilePath(application.ExecutableFile, true, true, false); // get the default application name from the executable file. FileInfo executableFileInfo = new FileInfo(executableFile); string applicationName = executableFileInfo.Name.Substring(0, executableFileInfo.Name.Length - 4); // choose a default configuration file. if (String.IsNullOrEmpty(application.ConfigurationFile)) { application.ConfigurationFile = Utils.Format( "{0}\\{1}.Config.xml", executableFileInfo.DirectoryName, applicationName); } // validate the configuration file. string configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, false, false); // create a new file if one does not exist. bool useExisting = true; if (configurationFile == null) { configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, true, true); useExisting = false; } // create the default configuration file. if (useExisting) { try { Opc.Ua.Security.SecuredApplication existingSettings = new Opc.Ua.Security.SecurityConfigurationManager().ReadConfiguration(configurationFile); // copy current settings application.ApplicationType = existingSettings.ApplicationType; application.BaseAddresses = existingSettings.BaseAddresses; application.ApplicationCertificate = existingSettings.ApplicationCertificate; application.ApplicationName = existingSettings.ApplicationName; application.ProductName = existingSettings.ProductName; application.RejectedCertificatesStore = existingSettings.RejectedCertificatesStore; application.TrustedCertificateStore = existingSettings.TrustedCertificateStore; application.TrustedCertificates = existingSettings.TrustedCertificates; application.IssuerCertificateStore = existingSettings.IssuerCertificateStore; application.IssuerCertificates = application.IssuerCertificates; application.UseDefaultCertificateStores = false; } catch (Exception e) { useExisting = false; Utils.Trace("WARNING. Existing configuration file could not be loaded: {0}.\r\nReplacing with default: {1}", e.Message, configurationFile); File.Copy(configurationFile, configurationFile + ".bak", true); } } // create the configuration file from the default. if (!useExisting) { try { string installationFile = Utils.Format( "{0}\\Install\\{1}.Config.xml", executableFileInfo.Directory.Parent.FullName, applicationName); if (!File.Exists(installationFile)) { Utils.Trace("Could not find default configuation at: {0}", installationFile); } File.Copy(installationFile, configurationFile, true); Utils.Trace("File.Copy({0}, {1})", installationFile, configurationFile); } catch (Exception e) { Utils.Trace("Could not copy default configuation to: {0}. Error={1}.", configurationFile, e.Message); } } // create a default application name. if (String.IsNullOrEmpty(application.ApplicationName)) { application.ApplicationName = applicationName; } // create a default product name. if (String.IsNullOrEmpty(application.ProductName)) { application.ProductName = application.ApplicationName; } // create a default uri. if (String.IsNullOrEmpty(application.ApplicationUri)) { application.ApplicationUri = Utils.Format("http://localhost/{0}/{1}", applicationName, Guid.NewGuid()); } // make the uri specify the local machine. application.ApplicationUri = Utils.ReplaceLocalhost(application.ApplicationUri); // set a default application store. if (application.ApplicationCertificate == null) { application.ApplicationCertificate = new Opc.Ua.Security.CertificateIdentifier(); application.ApplicationCertificate.StoreType = Utils.DefaultStoreType; application.ApplicationCertificate.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; } if (application.UseDefaultCertificateStores) { if (application.IssuerCertificateStore == null) { application.IssuerCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.IssuerCertificateStore.StoreType = Utils.DefaultStoreType; application.IssuerCertificateStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; } if (application.TrustedCertificateStore == null) { application.TrustedCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.TrustedCertificateStore.StoreType = Utils.DefaultStoreType; application.TrustedCertificateStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; } try { Utils.GetAbsoluteDirectoryPath(application.TrustedCertificateStore.StorePath, true, true, true); } catch (Exception e) { Utils.Trace("Could not access the machine directory: {0} '{1}'", application.RejectedCertificatesStore.StorePath, e); } if (application.RejectedCertificatesStore == null) { application.RejectedCertificatesStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.RejectedCertificatesStore.StoreType = CertificateStoreType.Directory; application.RejectedCertificatesStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\RejectedCertificates"; StringBuilder buffer = new StringBuilder(); buffer.Append(ApplicationData.Current.LocalFolder.Path); buffer.Append("\\OPC Foundation"); buffer.Append("\\RejectedCertificates"); string folderPath = buffer.ToString(); if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } } } // check for valid certificate (discard invalid certificates). CertificateIdentifier applicationCertificate = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(application.ApplicationCertificate); X509Certificate2 certificate = await applicationCertificate.Find(true); if (certificate == null) { certificate = await applicationCertificate.Find(false); if (certificate != null) { Utils.Trace( "Found existing certificate but it does not have a private key: Store={0}, Certificate={1}", application.ApplicationCertificate.StorePath, application.ApplicationCertificate); } else { Utils.Trace( "Existing certificate could not be found: Store={0}, Certificate={1}", application.ApplicationCertificate.StorePath, application.ApplicationCertificate); } } // check if no certificate exists. if (certificate == null) { certificate = await CreateCertificateForApplication(application); } // ensure the application certificate is in the trusted peers store. try { CertificateStoreIdentifier certificateStore = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(application.TrustedCertificateStore); using (ICertificateStore store = certificateStore.OpenStore()) { X509Certificate2Collection peerCertificates = await store.FindByThumbprint(certificate.Thumbprint); if (peerCertificates.Count == 0) { await store.Add(new X509Certificate2(certificate.RawData)); } } } catch (Exception e) { Utils.Trace( "Could not add certificate '{0}' to trusted peer store '{1}'. Error={2}", certificate.Subject, application.TrustedCertificateStore, e.Message); } // update configuration file location. UpdateConfigurationLocation(executableFile, configurationFile); // update configuration file. new Opc.Ua.Security.SecurityConfigurationManager().WriteConfiguration(configurationFile, application); ApplicationAccessRuleCollection accessRules = application.AccessRules; bool noRulesDefined = application.AccessRules == null || application.AccessRules.Count == 0; // add the default access rules. if (noRulesDefined) { ApplicationAccessRule rule = new ApplicationAccessRule(); rule.IdentityName = WellKnownSids.Administrators; rule.RuleType = AccessControlType.Allow; rule.Right = ApplicationAccessRight.Configure; accessRules.Add(rule); rule = new ApplicationAccessRule(); rule.IdentityName = WellKnownSids.Users; rule.RuleType = AccessControlType.Allow; rule.Right = ApplicationAccessRight.Update; accessRules.Add(rule); } // ensure the service account has priviledges. if (application.InstallAsService) { // check if a specific account is assigned. AccountInfo accountInfo = null; if (!String.IsNullOrEmpty(application.ServiceUserName)) { accountInfo = AccountInfo.Create(application.ServiceUserName); } // choose a built-in service account. if (accountInfo == null) { accountInfo = AccountInfo.Create(WellKnownSids.NetworkService); if (accountInfo == null) { accountInfo = AccountInfo.Create(WellKnownSids.LocalSystem); } } ApplicationAccessRule rule = new ApplicationAccessRule(); rule.IdentityName = accountInfo.ToString(); rule.RuleType = AccessControlType.Allow; rule.Right = ApplicationAccessRight.Run; accessRules.Add(rule); } // set the permissions for the HTTP endpoints used by the application. if (configureFirewall && application.BaseAddresses != null && application.BaseAddresses.Count > 0) { for (int ii = 0; ii < application.BaseAddresses.Count; ii++) { Uri url = Utils.ParseUri(application.BaseAddresses[ii]); if (url != null) { try { HttpAccessRule.SetAccessRules(url, accessRules, true); Utils.Trace("Added HTTP access rules for URL: {0}", url); } catch (Exception e) { Utils.Trace("Could not set HTTP access rules for URL: {0}. Error={1}", url, e.Message); for (int jj = 0; jj < accessRules.Count; jj++) { ApplicationAccessRule rule = accessRules[jj]; Utils.Trace( (int)Utils.TraceMasks.Error, "IdentityName={0}, Right={1}, RuleType={2}", rule.IdentityName, rule.Right, rule.RuleType); } } } } } // set permissions on the local certificate store. SetCertificatePermissions( application, applicationCertificate, accessRules, false); // set permissions on the local certificate store. if (application.RejectedCertificatesStore != null) { // need to grant full control to certificates in the RejectedCertificatesStore. foreach (ApplicationAccessRule rule in accessRules) { if (rule.RuleType == AccessControlType.Allow) { rule.Right = ApplicationAccessRight.Configure; } } CertificateStoreIdentifier rejectedCertificates = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(application.RejectedCertificatesStore); using (ICertificateStore store = rejectedCertificates.OpenStore()) { if (store.SupportsAccessControl) { store.SetAccessRules(accessRules, false); } } } }
/// <summary> /// Uninstalls a UA application. /// </summary> public static async Task UninstallApplication(InstalledApplication application) { // validate the executable file. string executableFile = Utils.GetAbsoluteFilePath(application.ExecutableFile, true, true, false); // get the default application name from the executable file. FileInfo executableFileInfo = new FileInfo(executableFile); string applicationName = executableFileInfo.Name.Substring(0, executableFileInfo.Name.Length-4); // choose a default configuration file. if (String.IsNullOrEmpty(application.ConfigurationFile)) { application.ConfigurationFile = Utils.Format( "{0}\\{1}.Config.xml", executableFileInfo.DirectoryName, applicationName); } // validate the configuration file. string configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, false, false); if (configurationFile != null) { // load the current configuration. Opc.Ua.Security.SecuredApplication security = new Opc.Ua.Security.SecurityConfigurationManager().ReadConfiguration(configurationFile); // delete the application certificates. if (application.DeleteCertificatesOnUninstall) { CertificateIdentifier id = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(security.ApplicationCertificate); // delete public key from trusted peers certificate store. try { CertificateStoreIdentifier certificateStore = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(security.TrustedCertificateStore); using (ICertificateStore store = certificateStore.OpenStore()) { X509Certificate2Collection peerCertificates = await store.FindByThumbprint(id.Thumbprint); if (peerCertificates.Count > 0) { await store.Delete(peerCertificates[0].Thumbprint); } } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } // delete private key from application certificate store. try { using (ICertificateStore store = id.OpenStore()) { await store.Delete(id.Thumbprint); } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } // permentently delete any UA defined stores if they are now empty. try { WindowsCertificateStore store = new WindowsCertificateStore(); await store.Open("LocalMachine\\UA Applications"); X509Certificate2Collection collection = await store.Enumerate(); if (collection.Count == 0) { store.PermanentlyDeleteStore(); } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } } } }
/// <summary> /// Sets the defaults for all fields. /// </summary> /// <param name="application">The application.</param> private static void SetDefaults(InstalledApplication application) { // create a default product name. if (String.IsNullOrEmpty(application.ProductName)) { application.ProductName = application.ApplicationName; } // create a default uri. if (String.IsNullOrEmpty(application.ApplicationUri)) { application.ApplicationUri = Utils.Format("http://localhost/{0}/{1}", application.ApplicationName, Guid.NewGuid()); } // make the uri specify the local machine. application.ApplicationUri = Utils.ReplaceLocalhost(application.ApplicationUri); // set a default application store. if (application.ApplicationCertificate == null) { application.ApplicationCertificate = new Opc.Ua.Security.CertificateIdentifier(); application.ApplicationCertificate.StoreType = Utils.DefaultStoreType; application.ApplicationCertificate.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; application.ApplicationCertificate.SubjectName = application.ApplicationName; } if (application.IssuerCertificateStore == null) { application.IssuerCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.IssuerCertificateStore.StoreType = Utils.DefaultStoreType; application.IssuerCertificateStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; } if (application.TrustedCertificateStore == null) { application.TrustedCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.TrustedCertificateStore.StoreType = Utils.DefaultStoreType; application.TrustedCertificateStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; } try { Utils.GetAbsoluteDirectoryPath(application.ApplicationCertificate.StorePath, true, true, true); } catch (Exception e) { Utils.Trace("Could not access the machine directory: {0} '{1}'", application.ApplicationCertificate.StorePath, e); } if (application.RejectedCertificatesStore == null) { application.RejectedCertificatesStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.RejectedCertificatesStore.StoreType = CertificateStoreType.Directory; application.RejectedCertificatesStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\RejectedCertificates"; } if (application.RejectedCertificatesStore.StoreType == CertificateStoreType.Directory) { try { Utils.GetAbsoluteDirectoryPath(application.RejectedCertificatesStore.StorePath, true, true, true); } catch (Exception e) { Utils.Trace("Could not access rejected certificates directory: {0} '{1}'", application.RejectedCertificatesStore.StorePath, e); } } }
/// <summary> /// Creates a new certificate for application. /// </summary> /// <param name="application">The application.</param> private static async Task<X509Certificate2> CreateCertificateForApplication(InstalledApplication application) { // build list of domains. List<string> domains = new List<string>(); if (application.BaseAddresses != null) { foreach (string baseAddress in application.BaseAddresses) { Uri uri = Utils.ParseUri(baseAddress); if (uri != null) { string domain = uri.DnsSafeHost; if (String.Compare(domain, "localhost", StringComparison.OrdinalIgnoreCase) == 0) { domain = Utils.GetHostName(); } if (!Utils.FindStringIgnoreCase(domains, domain)) { domains.Add(domain); } } } } // must at least of the localhost. if (domains.Count == 0) { domains.Add(Utils.GetHostName()); } // create the certificate. X509Certificate2 certificate = await Opc.Ua.CertificateFactory.CreateCertificate( application.ApplicationCertificate.StoreType, application.ApplicationCertificate.StorePath, application.ApplicationUri, application.ApplicationName, Utils.Format("CN={0}/DC={1}", application.ApplicationName, domains[0]), domains, 1024, 300); CertificateIdentifier applicationCertificate = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(application.ApplicationCertificate); return await applicationCertificate.LoadPrivateKey(null); }
/// <summary> /// Installs a UA application. /// </summary> public static async Task InstallApplication( InstalledApplication application, bool autostart, bool configureFirewall) { // validate the executable file. string executableFile = Utils.GetAbsoluteFilePath(application.ExecutableFile, true, true, false); // get the default application name from the executable file. FileInfo executableFileInfo = new FileInfo(executableFile); string applicationName = executableFileInfo.Name.Substring(0, executableFileInfo.Name.Length-4); // choose a default configuration file. if (String.IsNullOrEmpty(application.ConfigurationFile)) { application.ConfigurationFile = Utils.Format( "{0}\\{1}.Config.xml", executableFileInfo.DirectoryName, applicationName); } // validate the configuration file. string configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, false, false); // create a new file if one does not exist. bool useExisting = true; if (configurationFile == null) { configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, true, true); useExisting = false; } // create the default configuration file. if (useExisting) { try { Opc.Ua.Security.SecuredApplication existingSettings = new Opc.Ua.Security.SecurityConfigurationManager().ReadConfiguration(configurationFile); // copy current settings application.ApplicationType = existingSettings.ApplicationType; application.BaseAddresses = existingSettings.BaseAddresses; application.ApplicationCertificate = existingSettings.ApplicationCertificate; application.ApplicationName = existingSettings.ApplicationName; application.ProductName = existingSettings.ProductName; application.RejectedCertificatesStore = existingSettings.RejectedCertificatesStore; application.TrustedCertificateStore = existingSettings.TrustedCertificateStore; application.TrustedCertificates = existingSettings.TrustedCertificates; application.IssuerCertificateStore = existingSettings.IssuerCertificateStore; application.IssuerCertificates = application.IssuerCertificates; application.UseDefaultCertificateStores = false; } catch (Exception e) { useExisting = false; Utils.Trace("WARNING. Existing configuration file could not be loaded: {0}.\r\nReplacing with default: {1}", e.Message, configurationFile); File.Copy(configurationFile, configurationFile + ".bak", true); } } // create the configuration file from the default. if (!useExisting) { try { string installationFile = Utils.Format( "{0}\\Install\\{1}.Config.xml", executableFileInfo.Directory.Parent.FullName, applicationName); if (!File.Exists(installationFile)) { Utils.Trace("Could not find default configuation at: {0}", installationFile); } File.Copy(installationFile, configurationFile, true); Utils.Trace("File.Copy({0}, {1})", installationFile, configurationFile); } catch (Exception e) { Utils.Trace("Could not copy default configuation to: {0}. Error={1}.", configurationFile, e.Message); } } // create a default application name. if (String.IsNullOrEmpty(application.ApplicationName)) { application.ApplicationName = applicationName; } // create a default product name. if (String.IsNullOrEmpty(application.ProductName)) { application.ProductName = application.ApplicationName; } // create a default uri. if (String.IsNullOrEmpty(application.ApplicationUri)) { application.ApplicationUri = Utils.Format("http://localhost/{0}/{1}", applicationName, Guid.NewGuid()); } // make the uri specify the local machine. application.ApplicationUri = Utils.ReplaceLocalhost(application.ApplicationUri); // set a default application store. if (application.ApplicationCertificate == null) { application.ApplicationCertificate = new Opc.Ua.Security.CertificateIdentifier(); application.ApplicationCertificate.StoreType = Utils.DefaultStoreType; application.ApplicationCertificate.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; } if (application.UseDefaultCertificateStores) { if (application.IssuerCertificateStore == null) { application.IssuerCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.IssuerCertificateStore.StoreType = Utils.DefaultStoreType; application.IssuerCertificateStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; } if (application.TrustedCertificateStore == null) { application.TrustedCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.TrustedCertificateStore.StoreType = Utils.DefaultStoreType; application.TrustedCertificateStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; } try { Utils.GetAbsoluteDirectoryPath(application.TrustedCertificateStore.StorePath, true, true, true); } catch (Exception e) { Utils.Trace("Could not access the machine directory: {0} '{1}'", application.RejectedCertificatesStore.StorePath, e); } if (application.RejectedCertificatesStore == null) { application.RejectedCertificatesStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.RejectedCertificatesStore.StoreType = CertificateStoreType.Directory; application.RejectedCertificatesStore.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\RejectedCertificates"; StringBuilder buffer = new StringBuilder(); buffer.Append(ApplicationData.Current.LocalFolder.Path); buffer.Append("\\OPC Foundation"); buffer.Append("\\RejectedCertificates"); string folderPath = buffer.ToString(); if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } } } // check for valid certificate (discard invalid certificates). CertificateIdentifier applicationCertificate = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(application.ApplicationCertificate); X509Certificate2 certificate = await applicationCertificate.Find(true); if (certificate == null) { certificate = await applicationCertificate.Find(false); if (certificate != null) { Utils.Trace( "Found existing certificate but it does not have a private key: Store={0}, Certificate={1}", application.ApplicationCertificate.StorePath, application.ApplicationCertificate); } else { Utils.Trace( "Existing certificate could not be found: Store={0}, Certificate={1}", application.ApplicationCertificate.StorePath, application.ApplicationCertificate); } } // check if no certificate exists. if (certificate == null) { certificate = await CreateCertificateForApplication(application); } // ensure the application certificate is in the trusted peers store. try { CertificateStoreIdentifier certificateStore = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(application.TrustedCertificateStore); using (ICertificateStore store = certificateStore.OpenStore()) { X509Certificate2Collection peerCertificates = await store.FindByThumbprint(certificate.Thumbprint); if (peerCertificates.Count == 0) { await store.Add(new X509Certificate2(certificate.RawData)); } } } catch (Exception e) { Utils.Trace( "Could not add certificate '{0}' to trusted peer store '{1}'. Error={2}", certificate.Subject, application.TrustedCertificateStore, e.Message); } // update configuration file location. UpdateConfigurationLocation(executableFile, configurationFile); // update configuration file. new Opc.Ua.Security.SecurityConfigurationManager().WriteConfiguration(configurationFile, application); ApplicationAccessRuleCollection accessRules = application.AccessRules; bool noRulesDefined = application.AccessRules == null || application.AccessRules.Count == 0; // add the default access rules. if (noRulesDefined) { ApplicationAccessRule rule = new ApplicationAccessRule(); rule.IdentityName = WellKnownSids.Administrators; rule.RuleType = AccessControlType.Allow; rule.Right = ApplicationAccessRight.Configure; accessRules.Add(rule); rule = new ApplicationAccessRule(); rule.IdentityName = WellKnownSids.Users; rule.RuleType = AccessControlType.Allow; rule.Right = ApplicationAccessRight.Update; accessRules.Add(rule); } // ensure the service account has priviledges. if (application.InstallAsService) { // check if a specific account is assigned. AccountInfo accountInfo = null; if (!String.IsNullOrEmpty(application.ServiceUserName)) { accountInfo = AccountInfo.Create(application.ServiceUserName); } // choose a built-in service account. if (accountInfo == null) { accountInfo = AccountInfo.Create(WellKnownSids.NetworkService); if (accountInfo == null) { accountInfo = AccountInfo.Create(WellKnownSids.LocalSystem); } } ApplicationAccessRule rule = new ApplicationAccessRule(); rule.IdentityName = accountInfo.ToString(); rule.RuleType = AccessControlType.Allow; rule.Right = ApplicationAccessRight.Run; accessRules.Add(rule); } // set permissions on the local certificate store. SetCertificatePermissions( application, applicationCertificate, accessRules, false); // set permissions on the local certificate store. if (application.RejectedCertificatesStore != null) { // need to grant full control to certificates in the RejectedCertificatesStore. foreach (ApplicationAccessRule rule in accessRules) { if (rule.RuleType == AccessControlType.Allow) { rule.Right = ApplicationAccessRight.Configure; } } CertificateStoreIdentifier rejectedCertificates = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(application.RejectedCertificatesStore); using (ICertificateStore store = rejectedCertificates.OpenStore()) { if (store.SupportsAccessControl) { store.SetAccessRules(accessRules, false); } } } }
/// <summary> /// Installs a UA application. /// </summary> public static void InstallApplication( InstalledApplication application, bool autostart, bool configureFirewall) { // validate the executable file. string executableFile = Utils.GetAbsoluteFilePath(application.ExecutableFile, true, true, false); // get the default application name from the executable file. FileInfo executableFileInfo = new FileInfo(executableFile); string applicationName = executableFileInfo.Name.Substring(0, executableFileInfo.Name.Length-4); // choose a default configuration file. if (String.IsNullOrEmpty(application.ConfigurationFile)) { application.ConfigurationFile = Utils.Format( "{0}\\{1}.Config.xml", executableFileInfo.DirectoryName, applicationName); } // validate the configuration file. string configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, false, false); // create a new file if one does not exist. bool useExisting = true; if (configurationFile == null) { configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, true, true); useExisting = false; } // create the default configuration file. if (useExisting) { try { Opc.Ua.Security.SecuredApplication existingSettings = new Opc.Ua.Security.SecurityConfigurationManager().ReadConfiguration(configurationFile); // copy current settings application.ApplicationType = existingSettings.ApplicationType; application.BaseAddresses = existingSettings.BaseAddresses; application.ApplicationCertificate = existingSettings.ApplicationCertificate; application.ApplicationName = existingSettings.ApplicationName; application.ProductName = existingSettings.ProductName; application.RejectedCertificatesStore = existingSettings.RejectedCertificatesStore; application.TrustedCertificateStore = existingSettings.TrustedCertificateStore; application.TrustedCertificates = existingSettings.TrustedCertificates; application.IssuerCertificateStore = existingSettings.IssuerCertificateStore; application.IssuerCertificates = application.IssuerCertificates; application.UseDefaultCertificateStores = false; } catch (Exception e) { useExisting = false; Utils.Trace("WARNING. Existing configuration file could not be loaded: {0}.\r\nReplacing with default: {1}", e.Message, configurationFile); File.Copy(configurationFile, configurationFile + ".bak", true); } } // create the configuration file from the default. if (!useExisting) { try { string installationFile = Utils.Format( "{0}\\Install\\{1}.Config.xml", executableFileInfo.Directory.Parent.FullName, applicationName); if (!File.Exists(installationFile)) { Utils.Trace("Could not find default configuation at: {0}", installationFile); } File.Copy(installationFile, configurationFile, true); Utils.Trace("File.Copy({0}, {1})", installationFile, configurationFile); } catch (Exception e) { Utils.Trace("Could not copy default configuation to: {0}. Error={1}.", configurationFile, e.Message); } } // create a default application name. if (String.IsNullOrEmpty(application.ApplicationName)) { application.ApplicationName = applicationName; } // create a default product name. if (String.IsNullOrEmpty(application.ProductName)) { application.ProductName = application.ApplicationName; } // create a default uri. if (String.IsNullOrEmpty(application.ApplicationUri)) { application.ApplicationUri = Utils.Format("http://localhost/{0}/{1}", applicationName, Guid.NewGuid()); } // make the uri specify the local machine. application.ApplicationUri = Utils.ReplaceLocalhost(application.ApplicationUri); // set a default application store. if (application.ApplicationCertificate == null) { application.ApplicationCertificate = new Opc.Ua.Security.CertificateIdentifier(); application.ApplicationCertificate.StoreType = Utils.DefaultStoreType; application.ApplicationCertificate.StorePath = Utils.DefaultStorePath; } if (application.UseDefaultCertificateStores) { if (application.IssuerCertificateStore == null) { application.IssuerCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.IssuerCertificateStore.StoreType = Utils.DefaultStoreType; application.IssuerCertificateStore.StorePath = Utils.DefaultStorePath; } if (application.TrustedCertificateStore == null) { application.TrustedCertificateStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.TrustedCertificateStore.StoreType = Utils.DefaultStoreType; application.TrustedCertificateStore.StorePath = Utils.DefaultStorePath; } try { Utils.GetAbsoluteDirectoryPath(application.TrustedCertificateStore.StorePath, true, true, true); } catch (Exception e) { Utils.Trace("Could not access the machine directory: {0} '{1}'", application.RejectedCertificatesStore.StorePath, e); } if (application.RejectedCertificatesStore == null) { application.RejectedCertificatesStore = new Opc.Ua.Security.CertificateStoreIdentifier(); application.RejectedCertificatesStore.StoreType = CertificateStoreType.Directory; application.RejectedCertificatesStore.StorePath = "%CommonApplicationData%\\OPC Foundation\\CertificateStores\\RejectedCertificates"; StringBuilder buffer = new StringBuilder(); buffer.Append(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)); buffer.Append("\\OPC Foundation"); buffer.Append("\\RejectedCertificates"); string folderPath = buffer.ToString(); if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } } } // check for valid certificate (discard invalid certificates). CertificateIdentifier applicationCertificate = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(application.ApplicationCertificate); X509Certificate2 certificate = applicationCertificate.Find(true); if (certificate == null) { certificate = applicationCertificate.Find(false); if (certificate != null) { Utils.Trace( "Found existing certificate but it does not have a private key: Store={0}, Certificate={1}", application.ApplicationCertificate.StorePath, application.ApplicationCertificate); } else { Utils.Trace( "Existing certificate could not be found: Store={0}, Certificate={1}", application.ApplicationCertificate.StorePath, application.ApplicationCertificate); } } // check if no certificate exists. if (certificate == null) { certificate = CreateCertificateForApplication(application); } // ensure the application certificate is in the trusted peers store. try { CertificateStoreIdentifier certificateStore = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(application.TrustedCertificateStore); using (ICertificateStore store = certificateStore.OpenStore()) { X509Certificate2 peerCertificate = store.FindByThumbprint(certificate.Thumbprint); if (peerCertificate == null) { store.Add(new X509Certificate2(certificate.GetRawCertData())); } } } catch (Exception e) { Utils.Trace( "Could not add certificate '{0}' to trusted peer store '{1}'. Error={2}", certificate.Subject, application.TrustedCertificateStore, e.Message); } // locally register the certficate OIDs. if (application.LocallyRegisterOIDs) { try { LocallyRegisterCertificateOIDs(certificate); } catch (Exception e) { Utils.Trace( "Could not register OIDs used for certificate '{0}'. Error={1}", certificate.Subject, e.Message); } } // update configuration file location. UpdateConfigurationLocation(executableFile, configurationFile); // update configuration file. new Opc.Ua.Security.SecurityConfigurationManager().WriteConfiguration(configurationFile, application); // configure firewall. if (configureFirewall && application.ConfigureFirewall) { if (application.BaseAddresses != null && application.BaseAddresses.Count > 0) { try { SetFirewallAccess(application, executableFile); } catch (Exception e) { Utils.Trace("Could not set firewall access for executable: {0}. Error={1}", executableFile, e.Message); } } } ApplicationAccessRuleCollection accessRules = application.AccessRules; bool noRulesDefined = application.AccessRules == null || application.AccessRules.Count == 0; // add the default access rules. if (noRulesDefined) { ApplicationAccessRule rule = new ApplicationAccessRule(); rule.IdentityName = WellKnownSids.Administrators; rule.RuleType = AccessControlType.Allow; rule.Right = ApplicationAccessRight.Configure; accessRules.Add(rule); rule = new ApplicationAccessRule(); rule.IdentityName = WellKnownSids.Users; rule.RuleType = AccessControlType.Allow; rule.Right = ApplicationAccessRight.Update; accessRules.Add(rule); } // ensure the service account has priviledges. if (application.InstallAsService) { // check if a specific account is assigned. AccountInfo accountInfo = null; if (!String.IsNullOrEmpty(application.ServiceUserName)) { accountInfo = AccountInfo.Create(application.ServiceUserName); } // choose a built-in service account. if (accountInfo == null) { accountInfo = AccountInfo.Create(WellKnownSids.NetworkService); if (accountInfo == null) { accountInfo = AccountInfo.Create(WellKnownSids.LocalSystem); } } ApplicationAccessRule rule = new ApplicationAccessRule(); rule.IdentityName = accountInfo.ToString(); rule.RuleType = AccessControlType.Allow; rule.Right = ApplicationAccessRight.Run; accessRules.Add(rule); } // set the permissions for the HTTP endpoints used by the application. if (configureFirewall && application.BaseAddresses != null && application.BaseAddresses.Count > 0) { for (int ii = 0; ii < application.BaseAddresses.Count; ii++) { Uri url = Utils.ParseUri(application.BaseAddresses[ii]); if (url != null) { if (url.Scheme == Uri.UriSchemeHttp || url.Scheme == Uri.UriSchemeHttps) { try { HttpAccessRule.SetAccessRules(url, accessRules, true); Utils.Trace("Added HTTP access rules for URL: {0}", url); } catch (Exception e) { Utils.Trace("Could not set HTTP access rules for URL: {0}. Error={1}", url, e.Message); for (int jj = 0; jj < accessRules.Count; jj++) { ApplicationAccessRule rule = accessRules[jj]; Utils.Trace( (int)Utils.TraceMasks.Error, "IdentityName={0}, Right={1}, RuleType={2}", rule.IdentityName, rule.Right, rule.RuleType); } } } } } } // set permissions on the local certificate store. SetCertificatePermissions( application, applicationCertificate, accessRules, false); // set permissions on the local certificate store. if (application.RejectedCertificatesStore != null) { // need to grant full control to certificates in the RejectedCertificatesStore. foreach (ApplicationAccessRule rule in accessRules) { if (rule.RuleType == AccessControlType.Allow) { rule.Right = ApplicationAccessRight.Configure; } } CertificateStoreIdentifier rejectedCertificates = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(application.RejectedCertificatesStore); using (ICertificateStore store = rejectedCertificates.OpenStore()) { if (store.SupportsAccessControl) { store.SetAccessRules(accessRules, false); } } } // install as a service. if (application.InstallAsService) { ServiceInstaller.UnInstallService(application.ApplicationName); StartMode startMode = application.ServiceStartMode; if (!autostart) { startMode = StartMode.Manual; } bool start = true; bool result = ServiceInstaller.InstallService( executableFileInfo.FullName, application.ApplicationName, application.ApplicationName, application.ServiceDescription, startMode, application.ServiceUserName, application.ServicePassword, ref start); if (!result) { throw new ApplicationException("Could not install service."); } } }
/// <summary> /// Uninstalls a UA application. /// </summary> public static void UninstallApplication(InstalledApplication application) { // validate the executable file. string executableFile = Utils.GetAbsoluteFilePath(application.ExecutableFile, true, true, false); // get the default application name from the executable file. FileInfo executableFileInfo = new FileInfo(executableFile); string applicationName = executableFileInfo.Name.Substring(0, executableFileInfo.Name.Length-4); // choose a default configuration file. if (String.IsNullOrEmpty(application.ConfigurationFile)) { application.ConfigurationFile = Utils.Format( "{0}\\{1}.Config.xml", executableFileInfo.DirectoryName, applicationName); } // install as a service. if (application.InstallAsService) { ServiceInstaller.UnInstallService(application.ApplicationName); } // validate the configuration file. string configurationFile = Utils.GetAbsoluteFilePath(application.ConfigurationFile, true, false, false); if (configurationFile != null) { // load the current configuration. Opc.Ua.Security.SecuredApplication security = new Opc.Ua.Security.SecurityConfigurationManager().ReadConfiguration(configurationFile); // delete the application certificates. if (application.DeleteCertificatesOnUninstall) { CertificateIdentifier id = Opc.Ua.Security.SecuredApplication.FromCertificateIdentifier(security.ApplicationCertificate); // delete public key from trusted peers certificate store. try { CertificateStoreIdentifier certificateStore = Opc.Ua.Security.SecuredApplication.FromCertificateStoreIdentifier(security.TrustedCertificateStore); using (ICertificateStore store = certificateStore.OpenStore()) { X509Certificate2 peerCertificate = store.FindByThumbprint(id.Thumbprint); if (peerCertificate != null) { store.Delete(peerCertificate.Thumbprint); } } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } // delete private key from application certificate store. try { using (ICertificateStore store = id.OpenStore()) { store.Delete(id.Thumbprint); } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } // permentently delete any UA defined stores if they are now empty. try { WindowsCertificateStore store = new WindowsCertificateStore(); store.Open("LocalMachine\\UA Applications"); if (store.Enumerate().Count == 0) { store.PermanentlyDeleteStore(); } } catch (Exception e) { Utils.Trace("Could not delete certificate '{0}' from store. Error={1}", id, e.Message); } } // configure firewall. if (application.ConfigureFirewall) { if (security.BaseAddresses != null && security.BaseAddresses.Count > 0) { try { RemoveFirewallAccess(security, executableFile); } catch (Exception e) { Utils.Trace("Could not remove firewall access for executable: {0}. Error={1}", executableFile, e.Message); } } } // remove the permissions for the HTTP endpoints used by the application. if (application.BaseAddresses != null && application.BaseAddresses.Count > 0) { List<ApplicationAccessRule> noRules = new List<ApplicationAccessRule>(); for (int ii = 0; ii < application.BaseAddresses.Count; ii++) { Uri url = Utils.ParseUri(application.BaseAddresses[ii]); if (url != null) { if (url.Scheme == Uri.UriSchemeHttp || url.Scheme == Uri.UriSchemeHttps) { try { HttpAccessRule.SetAccessRules(url, noRules, true); Utils.Trace("Removed HTTP access rules for URL: {0}", url); } catch (Exception e) { Utils.Trace("Could not remove HTTP access rules for URL: {0}. Error={1}", url, e.Message); } } } } } } }