/// <summary> /// Displays the dialog. /// </summary> public async Task <bool> ShowDialog(CertificateIdentifier certificateIdentifier) { CertificateStoreCTRL.StoreType = null; CertificateStoreCTRL.StorePath = null; PrivateKeyCB.SelectedIndex = 0; PropertiesCTRL.Initialize((X509Certificate2)null); if (certificateIdentifier != null) { X509Certificate2 certificate = await certificateIdentifier.Find(); CertificateStoreCTRL.StoreType = certificateIdentifier.StoreType; CertificateStoreCTRL.StorePath = certificateIdentifier.StorePath; if (certificate != null && certificateIdentifier.Find(true) != null) { PrivateKeyCB.SelectedIndex = 1; } else { PrivateKeyCB.SelectedIndex = 0; } PropertiesCTRL.Initialize(certificate); } if (ShowDialog() != DialogResult.OK) { return(false); } return(true); }
/// <summary> /// Displays the dialog. /// </summary> public bool ShowDialog(CertificateIdentifier certificateIdentifier) { CertificateStoreCTRL.StoreType = null; CertificateStoreCTRL.StorePath = null; PrivateKeyCB.SelectedIndex = 0; PropertiesCTRL.Initialize((X509Certificate2)null); if (certificateIdentifier != null) { X509Certificate2 certificate = certificateIdentifier.Find(); CertificateStoreCTRL.StoreType = certificateIdentifier.StoreType; CertificateStoreCTRL.StorePath = certificateIdentifier.StorePath; if (certificate != null && certificateIdentifier.Find(true) != null) { PrivateKeyCB.SelectedIndex = 1; } else { PrivateKeyCB.SelectedIndex = 0; } PropertiesCTRL.Initialize(certificate); } if (ShowDialog() != DialogResult.OK) { return false; } return true; }
/// <summary> /// Deletes an existing application instance certificate. /// </summary> /// <param name="configuration">The configuration instance that stores the configurable information for a UA application.</param> private static async Task DeleteApplicationInstanceCertificate(ApplicationConfiguration configuration) { // create a default certificate id none specified. CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate; if (id == null) { return; } // delete certificate and private key. X509Certificate2 certificate = await id.Find().ConfigureAwait(false); if (certificate != null) { Utils.LogCertificate(TraceMasks.Security, "Deleting application instance certificate and private key.", certificate); } // delete trusted peer certificate. if (configuration.SecurityConfiguration != null && configuration.SecurityConfiguration.TrustedPeerCertificates != null) { string thumbprint = id.Thumbprint; if (certificate != null) { thumbprint = certificate.Thumbprint; } if (!string.IsNullOrEmpty(thumbprint)) { using (ICertificateStore store = configuration.SecurityConfiguration.TrustedPeerCertificates.OpenStore()) { bool deleted = await store.Delete(thumbprint).ConfigureAwait(false); if (deleted) { Utils.LogInfo(TraceMasks.Security, "Application Instance Certificate [{0}] deleted from trusted store.", thumbprint); } } } } // delete certificate and private key from owner store. if (certificate != null) { using (ICertificateStore store = id.OpenStore()) { bool deleted = await store.Delete(certificate.Thumbprint).ConfigureAwait(false); if (deleted) { Utils.LogCertificate(TraceMasks.Security, "Application certificate and private key deleted.", certificate); } } } // erase the memory copy of the deleted certificate id.Certificate = null; }
/// <summary> /// Initializes the validator from the configuration for a token policy. /// </summary> /// <param name="issuerCertificate">The issuer certificate.</param> private SecurityTokenResolver CreateSecurityTokenResolver(CertificateIdentifier issuerCertificate) { if (issuerCertificate == null) { throw new ArgumentNullException("issuerCertificate"); } // find the certificate. X509Certificate2 certificate = issuerCertificate.Find(false); if (certificate == null) { throw ServiceResultException.Create( StatusCodes.BadCertificateInvalid, "Could not find issuer certificate: {0}", issuerCertificate); } // create a security token representing the certificate. List <SecurityToken> tokens = new List <SecurityToken>(); tokens.Add(new X509SecurityToken(certificate)); // create issued token resolver. SecurityTokenResolver tokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver( new System.Collections.ObjectModel.ReadOnlyCollection <SecurityToken>(tokens), false); return(tokenResolver); }
/// <summary> /// Creates a user identity for the policy. /// </summary> private IUserIdentity CreateUserIdentity(UserTokenPolicy policy) { if (policy == null || policy.TokenType == UserTokenType.Anonymous) { return(null); } if (policy.TokenType == UserTokenType.UserName) { return(new UserIdentity("SomeUser", "password")); } if (policy.TokenType == UserTokenType.Certificate) { X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly); try { foreach (X509Certificate2 certificate in store.Certificates) { if (certificate.HasPrivateKey) { return(new UserIdentity(certificate)); } } return(null); } finally { store.Close(); } } if (policy.TokenType == UserTokenType.IssuedToken) { CertificateIdentifier userid = new CertificateIdentifier(); userid.StoreType = CertificateStoreType.Windows; userid.StorePath = "LocalMachine\\Root"; userid.SubjectName = "UASampleRoot"; X509Certificate2 certificate = userid.Find(); X509SecurityToken signingToken = new X509SecurityToken(certificate); SamlSecurityToken token = CreateSAMLToken("*****@*****.**", signingToken); return(new UserIdentity(token)); } throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "User token policy is not supported."); }
/// <summary> /// Creates a minimal endpoint description which allows a client to connect to a server. /// </summary> /// <remarks> /// In most cases the client will use the server's discovery endpoint to fetch the information /// constained in this structure. /// </remarks> public static EndpointDescription CreateEndpointDescription() { // create the endpoint description. EndpointDescription endpointDescription = new EndpointDescription(); endpointDescription.EndpointUrl = Utils.Format("http://{0}:61211/UA/SampleClient", System.Net.Dns.GetHostName()); // endpointDescription.EndpointUrl = Utils.Format("opc.tcp://{0}:51210/UA/SampleServer", System.Net.Dns.GetHostName()); // endpointDescription.EndpointUrl = Utils.Format("http://{0}:51211/UA/SampleServer/None", System.Net.Dns.GetHostName()); // endpointDescription.EndpointUrl = Utils.Format("http://{0}:51211/UA/SampleServer", System.Net.Dns.GetHostName()); // specify the security policy to use. // endpointDescription.SecurityPolicyUri = SecurityPolicies.None; // endpointDescription.SecurityMode = MessageSecurityMode.None;; endpointDescription.SecurityPolicyUri = SecurityPolicies.Basic256Sha256; endpointDescription.SecurityMode = MessageSecurityMode.SignAndEncrypt; // specify the transport profile. endpointDescription.TransportProfileUri = Profiles.WsHttpXmlOrBinaryTransport; // endpointDescription.TransportProfileUri = Profiles.WsHttpXmlTransport; // endpointDescription.TransportProfileUri = Profiles.UaTcpTransport; endpointDescription.Server.DiscoveryUrls.Add(Utils.Format("http://{0}:61211/UA/SampleClient/discovery", System.Net.Dns.GetHostName())); // load the the server certificate from the local certificate store. CertificateIdentifier certificateIdentifier = new CertificateIdentifier(); certificateIdentifier.StoreType = CertificateStoreType.Windows; certificateIdentifier.StorePath = "LocalMachine\\My"; certificateIdentifier.SubjectName = "UA Sample Client"; X509Certificate2 serverCertificate = certificateIdentifier.Find(); if (serverCertificate == null) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "Could not find server certificate: {0}", certificateIdentifier.SubjectName); } endpointDescription.ServerCertificate = serverCertificate.RawData; return(endpointDescription); }
/// <summary> /// Deletes an existing application instance certificate. /// </summary> /// <param name="configuration">The configuration instance that stores the configurable information for a UA application.</param> private static async Task DeleteApplicationInstanceCertificate(ApplicationConfiguration configuration) { Utils.Trace(Utils.TraceMasks.Information, "Deleting application instance certificate."); // create a default certificate id none specified. CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate; if (id == null) { return; } // delete private key. X509Certificate2 certificate = await id.Find().ConfigureAwait(false); // delete trusted peer certificate. if (configuration.SecurityConfiguration != null && configuration.SecurityConfiguration.TrustedPeerCertificates != null) { string thumbprint = id.Thumbprint; if (certificate != null) { thumbprint = certificate.Thumbprint; } if (!string.IsNullOrEmpty(thumbprint)) { using (ICertificateStore store = configuration.SecurityConfiguration.TrustedPeerCertificates.OpenStore()) { await store.Delete(thumbprint).ConfigureAwait(false); } } } // delete private key. if (certificate != null) { using (ICertificateStore store = id.OpenStore()) { await store.Delete(certificate.Thumbprint).ConfigureAwait(false); } } }
/// <summary> /// Deletes an existing application instance certificate. /// </summary> /// <param name="configuration">The configuration instance that stores the configurable information for a UA application.</param> private static void DeleteApplicationInstanceCertificate(ApplicationConfiguration configuration) { Utils.Trace(Utils.TraceMasks.Information, "Deleting application instance certificate."); // Create a default certificate id none specified. CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate; if (id == null) { return; } X509Certificate2 certificate = id.Find(); // Delete trusted peer certificate. if (configuration.SecurityConfiguration?.TrustedPeerCertificates != null) { var thumbprint = id.Thumbprint; if (certificate != null) { thumbprint = certificate.Thumbprint; } using (var store = configuration.SecurityConfiguration.TrustedPeerCertificates.OpenStore()) { store.Delete(thumbprint); } } // Delete private key. if (certificate == null) { return; } using (ICertificateStore store = id.OpenStore()) { store.Delete(certificate.Thumbprint); } }
/// <summary> /// Deletes an existing application instance certificate. /// </summary> /// <param name="configuration">The configuration instance that stores the configurable information for a UA application.</param> public static void DeleteApplicationInstanceCertificate(ApplicationConfiguration configuration) { // create a default certificate id none specified. CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate; if (id == null) { return; } // delete private key. X509Certificate2 certificate = id.Find(); // delete trusted peer certificate. if (configuration.SecurityConfiguration != null && configuration.SecurityConfiguration.TrustedPeerCertificates != null) { string thumbprint = id.Thumbprint; if (certificate != null) { thumbprint = certificate.Thumbprint; } if (!String.IsNullOrEmpty(thumbprint)) { using (ICertificateStore store = configuration.SecurityConfiguration.TrustedPeerCertificates.OpenStore()) { store.Delete(thumbprint); } } } // delete private key. if (certificate != null) { using (ICertificateStore store = id.OpenStore()) { store.Delete(certificate.Thumbprint); } } }
private void CertificateBTN_Click(object sender, EventArgs e) { try { // determine default store. CertificateStoreIdentifier store = new CertificateStoreIdentifier(); if (m_certificate != null) { store.StoreType = m_certificate.StoreType; store.StorePath = m_certificate.StorePath; } else { store.StoreType = Utils.DefaultStoreType; store.StorePath = Utils.DefaultStorePath; } // select the certificate. CertificateIdentifier certificate = new CertificateListDlg().ShowDialog(store, true); if (certificate != null) { m_certificate = certificate; X509Certificate2 certificate2 = m_certificate.Find(); if (certificate2 != null) { CertificateTB.Text = certificate2.Subject; } else { CertificateTB.Text = m_certificate.ToString(); } } } catch (Exception exception) { GuiUtils.HandleException(this.Text, System.Reflection.MethodBase.GetCurrentMethod(), exception); } }
/// <summary> /// Updates the dialog with the configuration. /// </summary> private void Update(ManagedApplication application) { if (application == null) { application = new ManagedApplication(); } m_application = application; SetIsSdkApplication(application.IsSdkCompatible); ApplicationNameTB.Text = application.DisplayName; ExecutableFileTB.Text = application.ExecutablePath; ConfigurationFileTB.Text = application.ConfigurationPath; CertificateTB.Text = null; TrustListTB.Text = null; m_certificate = application.Certificate; m_trustList = application.TrustList; if (m_certificate != null) { X509Certificate2 certificate = m_certificate.Find(); if (certificate != null) { CertificateTB.Text = certificate.Subject; } else { CertificateTB.Text = m_certificate.ToString(); } } if (m_trustList != null) { TrustListTB.Text = m_trustList.ToString(); } }
/// <summary> /// Creates a minimal endpoint description which allows a client to connect to a server. /// </summary> /// <remarks> /// In most cases the client will use the server's discovery endpoint to fetch the information /// constained in this structure. /// </remarks> public static EndpointDescription CreateEndpointDescription(string Url) { // create the endpoint description. EndpointDescription endpointDescription = new EndpointDescription(); //endpointDescription.EndpointUrl = Utils.Format("opc.tcp://{0}:4840", System.Net.Dns.GetHostName()); endpointDescription.EndpointUrl = Url; // specify the security policy to use. //endpointDescription.SecurityPolicyUri = SecurityPolicies.Basic128Rsa15; endpointDescription.SecurityPolicyUri = SecurityPolicies.None; //endpointDescription.SecurityMode = MessageSecurityMode.SignAndEncrypt; endpointDescription.SecurityMode = MessageSecurityMode.None; // specify the transport profile. endpointDescription.TransportProfileUri = Profiles.WsHttpXmlOrBinaryTransport; // load the the server certificate from the local certificate store. CertificateIdentifier certificateIdentifier = new CertificateIdentifier(); certificateIdentifier.StoreType = CertificateStoreType.Windows; certificateIdentifier.StorePath = "LocalMachine\\My"; certificateIdentifier.SubjectName = "UA Test Client"; X509Certificate2 serverCertificate = certificateIdentifier.Find(); if (serverCertificate == null) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "Could not find server certificate in certificate store: {0}", certificateIdentifier.SubjectName); } endpointDescription.ServerCertificate = serverCertificate.GetRawCertData(); return(endpointDescription); }
/// <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.LogInfo("Checking application instance certificate."); if (m_applicationConfiguration == null) { await LoadApplicationConfiguration(silent).ConfigureAwait(false); } ApplicationConfiguration configuration = m_applicationConfiguration; // find the existing certificate. CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate; if (id == null) { throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "Configuration file does not specify a certificate."); } // reload the certificate from disk in the cache. var passwordProvider = configuration.SecurityConfiguration.CertificatePasswordProvider; await configuration.SecurityConfiguration.ApplicationCertificate.LoadPrivateKeyEx(passwordProvider).ConfigureAwait(false); // load the certificate X509Certificate2 certificate = await id.Find(true).ConfigureAwait(false); // check that it is ok. if (certificate != null) { Utils.LogCertificate("Check certificate:", certificate); bool certificateValid = await CheckApplicationInstanceCertificate(configuration, certificate, silent, minimumKeySize).ConfigureAwait(false); if (!certificateValid) { var message = new StringBuilder(); message.AppendLine("The certificate with subject {0} in the configuration is invalid."); message.AppendLine(" Please update or delete the certificate from this location:"); message.AppendLine(" {1}"); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message.ToString(), id.SubjectName, id.StorePath ); } } 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 { StoreType = id.StoreType, StorePath = id.StorePath, 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) { 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); }
/// <summary> /// Creates a user identity for the policy. /// </summary> private IUserIdentity CreateUserIdentity(UserTokenPolicy policy) { if (policy == null || policy.TokenType == UserTokenType.Anonymous) { return null; } if (policy.TokenType == UserTokenType.UserName) { return new UserIdentity("SomeUser", "password"); } if (policy.TokenType == UserTokenType.Certificate) { X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly); try { foreach (X509Certificate2 certificate in store.Certificates) { if (certificate.HasPrivateKey) { return new UserIdentity(certificate); } } return null; } finally { store.Close(); } } if (policy.TokenType == UserTokenType.IssuedToken) { CertificateIdentifier userid = new CertificateIdentifier(); userid.StoreType = CertificateStoreType.Windows; userid.StorePath = "LocalMachine\\Root"; userid.SubjectName = "UASampleRoot"; X509Certificate2 certificate = userid.Find(); X509SecurityToken signingToken = new X509SecurityToken(certificate); SamlSecurityToken token = CreateSAMLToken("*****@*****.**", signingToken); return new UserIdentity(token); } throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "User token policy is not supported."); }
/// <summary> /// Updates the dialog with the configuration. /// </summary> private void Update(ManagedApplication application) { if (application == null) { application = new ManagedApplication(); } m_application = application; SetIsSdkApplication(application.IsSdkCompatible); ApplicationNameTB.Text = application.DisplayName; ExecutableFileTB.Text = application.ExecutablePath; ConfigurationFileTB.Text = application.ConfigurationPath; CertificateTB.Text = null; TrustListTB.Text = null; m_certificate = application.Certificate; m_trustList = application.TrustList; if (m_certificate != null) { X509Certificate2 certificate = m_certificate.Find(); if (certificate != null) { CertificateTB.Text = certificate.Subject; } else { CertificateTB.Text = m_certificate.ToString(); } } if (m_trustList != null) { TrustListTB.Text = m_trustList.ToString(); } }
private void CertificateBTN_Click(object sender, EventArgs e) { try { // determine default store. CertificateStoreIdentifier store = new CertificateStoreIdentifier(); if (m_certificate != null) { store.StoreType = m_certificate.StoreType; store.StorePath = m_certificate.StorePath; } else { store.StoreType = Utils.DefaultStoreType; store.StorePath = Utils.DefaultStorePath; } // select the certificate. CertificateIdentifier certificate = new CertificateListDlg().ShowDialog(store, true); if (certificate != null) { m_certificate = certificate; X509Certificate2 certificate2 = m_certificate.Find(); if (certificate2 != null) { CertificateTB.Text = certificate2.Subject; } else { CertificateTB.Text = m_certificate.ToString(); } } } catch (Exception exception) { GuiUtils.HandleException(this.Text, System.Reflection.MethodBase.GetCurrentMethod(), exception); } }
public async Task Initialize( GlobalDiscoveryClientConfiguration configuration, GlobalDiscoveryServerClient gds, ServerPushConfigurationClient server, RegisteredApplication application, bool isHttps) { m_configuration = configuration; m_gds = gds; m_server = server; m_application = application; m_certificate = null; m_certificatePassword = null; CertificateRequestTimer.Enabled = false; RequestProgressLabel.Visible = false; ApplyChangesButton.Enabled = false; CertificateControl.ShowNothing(); X509Certificate2 certificate = null; if (!isHttps) { if (server.Endpoint != null && server.Endpoint.Description.ServerCertificate != null) { certificate = new X509Certificate2(server.Endpoint.Description.ServerCertificate); } else if (application != null) { if (!String.IsNullOrEmpty(application.CertificatePublicKeyPath)) { string file = Utils.GetAbsoluteFilePath(application.CertificatePublicKeyPath, true, false, false); if (file != null) { certificate = new X509Certificate2(file); } } else if (!String.IsNullOrEmpty(application.CertificateStorePath)) { CertificateIdentifier id = new CertificateIdentifier { StorePath = application.CertificateStorePath }; id.StoreType = CertificateStoreIdentifier.DetermineStoreType(id.StorePath); id.SubjectName = application.CertificateSubjectName.Replace("localhost", Utils.GetHostName()); certificate = await id.Find(true); } } } else { if (application != null) { if (!String.IsNullOrEmpty(application.HttpsCertificatePublicKeyPath)) { string file = Utils.GetAbsoluteFilePath(application.HttpsCertificatePublicKeyPath, true, false, false); if (file != null) { certificate = new X509Certificate2(file); } } else { foreach (string disoveryUrl in application.DiscoveryUrl) { if (Uri.IsWellFormedUriString(disoveryUrl, UriKind.Absolute)) { Uri url = new Uri(disoveryUrl); CertificateIdentifier id = new CertificateIdentifier() { StoreType = CertificateStoreType.X509Store, StorePath = "CurrentUser\\UA_MachineDefault", SubjectName = "CN=" + url.DnsSafeHost }; certificate = await id.Find(); } } } } } if (certificate != null) { try { CertificateControl.Tag = certificate.Thumbprint; } catch (Exception) { MessageBox.Show( Parent, "The certificate does not appear to be valid. Please check configuration settings.", Parent.Text, MessageBoxButtons.OK, MessageBoxIcon.Error); certificate = null; } } WarningLabel.Visible = certificate == null; if (certificate != null) { m_certificate = certificate; CertificateControl.ShowValue(null, "Application Certificate", new CertificateWrapper() { Certificate = certificate }, true); } }
/// <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."); ApplicationConfiguration configuration = null; if (m_applicationConfiguration == null) { await LoadApplicationConfiguration(silent); } 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); // check that it is ok. if (certificate != null) { certificateValid = await CheckApplicationInstanceCertificate(configuration, certificate, silent, minimumKeySize); } else { // check for missing private key. certificate = await id.Find(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); } if (certificate != null) { string message = Utils.Format( "Thumbprint was explicitly specified in the configuration." + "\r\nAnother certificate with the same subject name was found." + "\r\nUse it instead?\r\n" + "\r\nRequested: {0}" + "\r\nFound: {1}", id.SubjectName, certificate.Subject); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message); } else { string message = Utils.Format("Thumbprint was explicitly specified in the configuration. Cannot generate a new certificate."); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message); } } } if ((certificate == null) || !certificateValid) { certificate = await CreateApplicationInstanceCertificate(configuration, minimumKeySize, lifeTimeInMonths); if (certificate == null) { string message = Utils.Format( "There is no cert with subject {0} in the configuration." + "\r\n Please generate a cert for your application,", "\r\n then copy the new cert to this location:" + "\r\n{1}", id.SubjectName, id.StorePath); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message); } } else { if (configuration.SecurityConfiguration.AddAppCertToTrustedStore) { // ensure it is trusted. await AddToTrustedStore(configuration, certificate); } } return(true); }
private async Task RequestNewCertificatePullMode(object sender, EventArgs e) { try { // check if we already have a private key NodeId requestId = null; if (!string.IsNullOrEmpty(m_application.CertificateStorePath)) { CertificateIdentifier id = new CertificateIdentifier { StoreType = CertificateStoreIdentifier.DetermineStoreType(m_application.CertificateStorePath), StorePath = m_application.CertificateStorePath, SubjectName = m_application.CertificateSubjectName.Replace("localhost", Utils.GetHostName()) }; m_certificate = await id.Find(true); if (m_certificate != null && m_certificate.HasPrivateKey) { m_certificate = await id.LoadPrivateKey(m_certificatePassword); } } bool hasPrivateKeyFile = false; if (!string.IsNullOrEmpty(m_application.CertificatePrivateKeyPath)) { FileInfo file = new FileInfo(m_application.CertificatePrivateKeyPath); hasPrivateKeyFile = file.Exists; } var domainNames = m_application.GetDomainNames(m_certificate); if (m_certificate == null) { // no private key requestId = m_gds.StartNewKeyPairRequest( m_application.ApplicationId, null, null, m_application.CertificateSubjectName.Replace("localhost", Utils.GetHostName()), domainNames, "PFX", m_certificatePassword); } else { X509Certificate2 csrCertificate = null; if (m_certificate.HasPrivateKey) { csrCertificate = m_certificate; } else { string absoluteCertificatePrivateKeyPath = Utils.GetAbsoluteFilePath(m_application.CertificatePrivateKeyPath, true, false, false); byte[] pkcsData = File.ReadAllBytes(absoluteCertificatePrivateKeyPath); if (m_application.GetPrivateKeyFormat(m_server?.GetSupportedKeyFormats()) == "PFX") { csrCertificate = CertificateFactory.CreateCertificateFromPKCS12(pkcsData, m_certificatePassword); } else { csrCertificate = CertificateFactory.CreateCertificateWithPEMPrivateKey(m_certificate, pkcsData, m_certificatePassword); } } byte[] certificateRequest = CertificateFactory.CreateSigningRequest(csrCertificate, domainNames); requestId = m_gds.StartSigningRequest(m_application.ApplicationId, null, null, certificateRequest); } m_application.CertificateRequestId = requestId.ToString(); CertificateRequestTimer.Enabled = true; RequestProgressLabel.Visible = true; WarningLabel.Visible = false; } catch (Exception ex) { Opc.Ua.Client.Controls.ExceptionDlg.Show(Text, ex); } }
/// <summary> /// Checks for a valid application instance certificate. /// </summary> /// <param name="configuration">Config of UA application.</param> /// <param name="silent">If set to <c>true</c> no dialogs will be displayed.</param> /// <param name="minimumKeySize">Minimum size of the key.</param> public static void CheckApplicationInstanceCertificate( ApplicationConfiguration configuration, bool silent, ushort minimumKeySize) { Utils.Trace(Utils.TraceMasks.Information, "Checking application instance certificate."); bool createNewCertificate = true; // 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 = id.Find(true); // check that it is ok. if (certificate != null) { createNewCertificate = !CheckApplicationInstanceCertificate(configuration, certificate, silent, minimumKeySize); } else { // check for missing private key. certificate = id.Find(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 { StoreType = id.StoreType, StorePath = id.StorePath, SubjectName = id.SubjectName }; certificate = id2.Find(true); } if (certificate != null) { string message = Utils.Format( "Thumbprint was explicitly specified in the configuration." + "\r\nAnother certificate with the same subject name was found." + "\r\nUse it instead?\r\n" + "\r\nRequested: {0}" + "\r\nFound: {1}", id.SubjectName, certificate.Subject); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message); } else { string message = Utils.Format("Thumbprint was explicitly specified in the configuration. Cannot generate a new certificate."); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message); } } else if (string.IsNullOrEmpty(id.SubjectName)) { string message = Utils.Format("Both SubjectName and Thumbprint are not specified in the configuration. Cannot generate a new certificate."); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message); } } // create a new certificate. if (createNewCertificate) { certificate = CreateApplicationInstanceCertificate(configuration, minimumKeySize, 600); configuration.SecurityConfiguration.ApplicationCertificate.Certificate = certificate; } // Make sure cert is in trusted store else { AddToTrustedStore(configuration, certificate); configuration.SecurityConfiguration.ApplicationCertificate.Certificate = certificate; } }
/// <summary> /// Displays the dialog. /// </summary> public bool ShowDialog(CertificateIdentifier certificate) { m_certificate = certificate; CertificateStoreCTRL.StoreType = null; CertificateStoreCTRL.StorePath = null; CertificateStoreCTRL.ReadOnly = true; ApplicationNameTB.Text = null; ApplicationUriTB.Text = null; OrganizationTB.Text = null; DomainsTB.Text = System.Net.Dns.GetHostName(); SubjectNameTB.Text = null; IssuerNameTB.Text = null; ValidFromTB.Text = null; ValidToTB.Text = null; ThumbprintTB.Text = null; if (certificate != null) { CertificateStoreCTRL.StoreType = certificate.StoreType; CertificateStoreCTRL.StorePath = certificate.StorePath; SubjectNameTB.Text = certificate.SubjectName; ThumbprintTB.Text = certificate.Thumbprint; X509Certificate2 data = certificate.Find(); if (data != null) { // fill in subject name. StringBuilder buffer = new StringBuilder(); foreach (string element in Utils.ParseDistinguishedName(data.Subject)) { if (element.StartsWith("CN=")) { ApplicationNameTB.Text = element.Substring(3); } if (element.StartsWith("O=")) { OrganizationTB.Text = element.Substring(2); } if (buffer.Length > 0) { buffer.Append('/'); } buffer.Append(element); } if (buffer.Length > 0) { SubjectNameTB.Text = buffer.ToString(); } // fill in issuer name. buffer = new StringBuilder(); foreach (string element in Utils.ParseDistinguishedName(data.Issuer)) { if (buffer.Length > 0) { buffer.Append('/'); } buffer.Append(element); } if (buffer.Length > 0) { IssuerNameTB.Text = buffer.ToString(); } // fill in application uri. string applicationUri = Utils.GetApplicationUriFromCertficate(data); if (!String.IsNullOrEmpty(applicationUri)) { ApplicationUriTB.Text = applicationUri; } // fill in domains. buffer = new StringBuilder(); foreach (string domain in Utils.GetDomainsFromCertficate(data)) { if (buffer.Length > 0) { buffer.Append(", "); } buffer.Append(domain); } if (buffer.Length > 0) { DomainsTB.Text = buffer.ToString(); } ValidFromTB.Text = data.NotBefore.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); ValidToTB.Text = data.NotAfter.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); ThumbprintTB.Text = data.Thumbprint; } } if (ShowDialog() != DialogResult.OK) { return false; } return true; }
/// <summary> /// Creates an application instance certificate if one does not already exist. /// </summary> public static X509Certificate2 CheckApplicationInstanceCertificate( ApplicationConfiguration configuration, ushort keySize, bool interactive, bool updateFile) { // create a default certificate id none specified. CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate; if (id == null) { id = new CertificateIdentifier(); id.StoreType = Utils.DefaultStoreType; id.StorePath = Utils.DefaultStorePath; id.SubjectName = configuration.ApplicationName; } bool createNewCertificate = false; IList<string> serverDomainNames = configuration.GetServerDomainNames(); // check for private key. X509Certificate2 certificate = id.Find(true); if (certificate == null) { // check if config file has wrong thumprint. if (!String.IsNullOrEmpty(id.SubjectName) && !String.IsNullOrEmpty(id.Thumbprint)) { CertificateIdentifier id2 = new CertificateIdentifier(); id2.StoreType = id.StoreType; id2.StorePath = id.StorePath; id2.SubjectName = id.SubjectName; id = id2; certificate = id2.Find(true); if (certificate != null) { string message = Utils.Format( "Matching certificate with SubjectName={0} found but with a different thumbprint. Use certificate?", id.SubjectName); if (interactive) { if (MessageBox.Show(message, configuration.ApplicationName, MessageBoxButtons.YesNo) == DialogResult.No) { certificate = null; } } } } } // check if private key is missing. if (certificate == null) { certificate = id.Find(false); if (certificate != null) { string message = Utils.Format( "Matching certificate with SubjectName={0} found but without a private key. Create a new certificate?", id.SubjectName); if (interactive) { if (MessageBox.Show(message, configuration.ApplicationName, MessageBoxButtons.YesNo) == DialogResult.No) { certificate = null; } } } } // check domains. if (certificate != null) { IList<string> certificateDomainNames = Utils.GetDomainsFromCertficate(certificate); for (int ii = 0; ii < serverDomainNames.Count; ii++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, serverDomainNames[ii])) { continue; } if (String.Compare(serverDomainNames[ii], "localhost", StringComparison.OrdinalIgnoreCase) == 0) { // check computer name. string computerName = System.Net.Dns.GetHostName(); if (Utils.FindStringIgnoreCase(certificateDomainNames, computerName)) { continue; } // check for aliases. System.Net.IPHostEntry entry = System.Net.Dns.GetHostEntry(computerName); bool found = false; for (int jj = 0; jj < entry.Aliases.Length; jj++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, entry.Aliases[jj])) { found = true; break; } } if (found) { continue; } // check for ip addresses. for (int jj = 0; jj < entry.AddressList.Length; jj++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, entry.AddressList[jj].ToString())) { found = true; break; } } if (found) { continue; } } string message = Utils.Format( "The server is configured to use domain '{0}' which does not appear in the certificate. Update certificate?", serverDomainNames[ii]); createNewCertificate = true; if (interactive) { if (MessageBox.Show(message, configuration.ApplicationName, MessageBoxButtons.YesNo) != DialogResult.Yes) { createNewCertificate = false; continue; } } Utils.Trace(message); break; } if (!createNewCertificate) { // check if key size matches. if (keySize == certificate.PublicKey.Key.KeySize) { AddToTrustedStore(configuration, certificate); return certificate; } } } // prompt user. if (interactive) { if (!createNewCertificate) { if (MessageBox.Show("Application does not have an instance certificate. Create one automatically?", configuration.ApplicationName, MessageBoxButtons.YesNo) == DialogResult.No) { return null; } } } // delete existing certificate. if (certificate != null) { DeleteApplicationInstanceCertificate(configuration); } // add the localhost. if (serverDomainNames.Count == 0) { serverDomainNames.Add(System.Net.Dns.GetHostName()); } certificate = Opc.Ua.CertificateFactory.CreateCertificate( id.StoreType, id.StorePath, configuration.ApplicationUri, configuration.ApplicationName, null, serverDomainNames, keySize, 300); id.Certificate = certificate; AddToTrustedStore(configuration, certificate); if (updateFile && !String.IsNullOrEmpty(configuration.SourceFilePath)) { configuration.SaveToFile(configuration.SourceFilePath); } configuration.CertificateValidator.Update(configuration.SecurityConfiguration); return configuration.SecurityConfiguration.ApplicationCertificate.LoadPrivateKey(null); }
/// <summary> /// Creates an application instance certificate if one does not already exist. /// </summary> public static async Task<X509Certificate2> CheckApplicationInstanceCertificate( ApplicationConfiguration configuration, ushort keySize, bool interactive, bool updateFile) { // create a default certificate if none is specified. CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate; if (id == null) { id = new CertificateIdentifier(); id.StoreType = Utils.DefaultStoreType; id.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; id.SubjectName = configuration.ApplicationName; } bool createNewCertificate = false; IList<string> serverDomainNames = configuration.GetServerDomainNames(); // check for private key. X509Certificate2 certificate = await id.Find(true); if (certificate == null) { // check if config file has wrong thumprint. if (!String.IsNullOrEmpty(id.SubjectName) && !String.IsNullOrEmpty(id.Thumbprint)) { CertificateIdentifier id2 = new CertificateIdentifier(); id2.StoreType = id.StoreType; id2.StorePath = id.StorePath; id2.SubjectName = id.SubjectName; id = id2; certificate = await id2.Find(true); if (certificate != null) { string message = Utils.Format( "Matching certificate with SubjectName={0} found but with a different thumbprint. Use certificate?", id.SubjectName); if (interactive) { MessageDlg dialog = new MessageDlg(message, MessageDlgButton.Yes, MessageDlgButton.No); MessageDlgButton result = await dialog.ShowAsync(); if (result != MessageDlgButton.Yes) { certificate = null; } } } } // check if private key is missing. if (certificate == null) { certificate = await id.Find(false); if (certificate != null) { string message = Utils.Format( "Matching certificate with SubjectName={0} found but without a private key. Create a new certificate?", id.SubjectName); if (interactive) { MessageDlg dialog = new MessageDlg(message, MessageDlgButton.Yes, MessageDlgButton.No); MessageDlgButton result = await dialog.ShowAsync(); if (result != MessageDlgButton.Yes) { certificate = null; } } } } // check domains. if (certificate != null) { IList<string> certificateDomainNames = Utils.GetDomainsFromCertficate(certificate); for (int ii = 0; ii < serverDomainNames.Count; ii++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, serverDomainNames[ii])) { continue; } if (String.Compare(serverDomainNames[ii], "localhost", StringComparison.OrdinalIgnoreCase) == 0) { // check computer name. string computerName = Utils.GetHostName(); if (Utils.FindStringIgnoreCase(certificateDomainNames, computerName)) { continue; } } string message = Utils.Format( "The server is configured to use domain '{0}' which does not appear in the certificate. Create new certificate?", serverDomainNames[ii]); createNewCertificate = true; if (interactive) { MessageDlg dialog = new MessageDlg(message, MessageDlgButton.Yes, MessageDlgButton.No); MessageDlgButton result = await dialog.ShowAsync(); if (result != MessageDlgButton.Yes) { createNewCertificate = false; continue; } } Utils.Trace(message); break; } if (!createNewCertificate) { // check if key size matches. if (keySize == certificate.GetRSAPublicKey().KeySize) { await AddToTrustedStore(configuration, certificate); return certificate; } } } // prompt user. if (interactive) { if (!createNewCertificate) { MessageDlg dialog = new MessageDlg("Application does not have an instance certificate.\n Create one automatically?", MessageDlgButton.Yes, MessageDlgButton.No); MessageDlgButton result = await dialog.ShowAsync(); if (result != MessageDlgButton.Yes) { return null; } } } // delete existing certificate. if (certificate != null) { await DeleteApplicationInstanceCertificate(configuration); } // add the localhost. if (serverDomainNames.Count == 0) { serverDomainNames.Add(Utils.GetHostName()); } certificate = await Opc.Ua.CertificateFactory.CreateCertificate( id.StoreType, id.StorePath, configuration.ApplicationUri, configuration.ApplicationName, null, serverDomainNames, keySize, 300); id.Certificate = certificate; await AddToTrustedStore(configuration, certificate); if (updateFile && !String.IsNullOrEmpty(configuration.SourceFilePath)) { configuration.SaveToFile(configuration.SourceFilePath); } await configuration.CertificateValidator.Update(configuration.SecurityConfiguration); return await configuration.SecurityConfiguration.ApplicationCertificate.LoadPrivateKey(null); } return certificate; }
/// <summary> /// Creates an application instance certificate if one does not already exist. /// </summary> public static async Task <X509Certificate2> CheckApplicationInstanceCertificate( ApplicationConfiguration configuration, ushort keySize, bool interactive, bool updateFile) { // create a default certificate if none is specified. CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate; if (id == null) { id = new CertificateIdentifier(); id.StoreType = Utils.DefaultStoreType; id.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault"; id.SubjectName = configuration.ApplicationName; } bool createNewCertificate = false; IList <string> serverDomainNames = configuration.GetServerDomainNames(); // check for private key. X509Certificate2 certificate = await id.Find(true); if (certificate == null) { // check if config file has wrong thumprint. if (!String.IsNullOrEmpty(id.SubjectName) && !String.IsNullOrEmpty(id.Thumbprint)) { CertificateIdentifier id2 = new CertificateIdentifier(); id2.StoreType = id.StoreType; id2.StorePath = id.StorePath; id2.SubjectName = id.SubjectName; id = id2; certificate = await id2.Find(true); if (certificate != null) { string message = Utils.Format( "Matching certificate with SubjectName={0} found but with a different thumbprint. Use certificate?", id.SubjectName); if (interactive) { MessageDlg dialog = new MessageDlg(message, MessageDlgButton.Yes, MessageDlgButton.No); MessageDlgButton result = await dialog.ShowAsync(); if (result != MessageDlgButton.Yes) { certificate = null; } } } } // check if private key is missing. if (certificate == null) { certificate = await id.Find(false); if (certificate != null) { string message = Utils.Format( "Matching certificate with SubjectName={0} found but without a private key. Create a new certificate?", id.SubjectName); if (interactive) { MessageDlg dialog = new MessageDlg(message, MessageDlgButton.Yes, MessageDlgButton.No); MessageDlgButton result = await dialog.ShowAsync(); if (result != MessageDlgButton.Yes) { certificate = null; } } } } // check domains. if (certificate != null) { IList <string> certificateDomainNames = Utils.GetDomainsFromCertficate(certificate); for (int ii = 0; ii < serverDomainNames.Count; ii++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, serverDomainNames[ii])) { continue; } if (String.Compare(serverDomainNames[ii], "localhost", StringComparison.OrdinalIgnoreCase) == 0) { // check computer name. string computerName = Utils.GetHostName(); if (Utils.FindStringIgnoreCase(certificateDomainNames, computerName)) { continue; } } string message = Utils.Format( "The server is configured to use domain '{0}' which does not appear in the certificate. Create new certificate?", serverDomainNames[ii]); createNewCertificate = true; if (interactive) { MessageDlg dialog = new MessageDlg(message, MessageDlgButton.Yes, MessageDlgButton.No); MessageDlgButton result = await dialog.ShowAsync(); if (result != MessageDlgButton.Yes) { createNewCertificate = false; continue; } } Utils.Trace(message); break; } if (!createNewCertificate) { // check if key size matches. if (keySize == certificate.GetRSAPublicKey().KeySize) { await AddToTrustedStore(configuration, certificate); return(certificate); } } } // prompt user. if (interactive) { if (!createNewCertificate) { MessageDlg dialog = new MessageDlg("Application does not have an instance certificate.\n Create one automatically?", MessageDlgButton.Yes, MessageDlgButton.No); MessageDlgButton result = await dialog.ShowAsync(); if (result != MessageDlgButton.Yes) { return(null); } } } // delete existing certificate. if (certificate != null) { await DeleteApplicationInstanceCertificate(configuration); } // add the localhost. if (serverDomainNames.Count == 0) { serverDomainNames.Add(Utils.GetHostName()); } certificate = await Opc.Ua.CertificateFactory.CreateCertificate( id.StoreType, id.StorePath, configuration.ApplicationUri, configuration.ApplicationName, null, serverDomainNames, keySize, 300); id.Certificate = certificate; await AddToTrustedStore(configuration, certificate); if (updateFile && !String.IsNullOrEmpty(configuration.SourceFilePath)) { configuration.SaveToFile(configuration.SourceFilePath); } await configuration.CertificateValidator.Update(configuration.SecurityConfiguration); return(await configuration.SecurityConfiguration.ApplicationCertificate.LoadPrivateKey(null)); } return(certificate); }
/// <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> public async Task<bool> CheckApplicationInstanceCertificate( bool silent, ushort minimumKeySize) { Utils.Trace(Utils.TraceMasks.Information, "Checking application instance certificate."); ApplicationConfiguration configuration = null; if (m_applicationConfiguration == null) { await LoadApplicationConfiguration(silent); } 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); // check that it is ok. if (certificate != null) { certificateValid = await CheckApplicationInstanceCertificate(configuration, certificate, silent, minimumKeySize); } else { // check for missing private key. certificate = await id.Find(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); } if (certificate != null) { string message = Utils.Format( "Thumbprint was explicitly specified in the configuration." + "\r\nAnother certificate with the same subject name was found." + "\r\nUse it instead?\r\n" + "\r\nRequested: {0}" + "\r\nFound: {1}", id.SubjectName, certificate.Subject); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message); } else { string message = Utils.Format("Thumbprint was explicitly specified in the configuration. Cannot generate a new certificate."); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message); } } } if ((certificate == null) || !certificateValid) { certificate = await CreateApplicationInstanceCertificate(configuration, minimumKeySize); if (certificate == null) { string message = Utils.Format( "There is no cert with subject {0} in the configuration." + "\r\n Please generate a cert for your application,", "\r\n then copy the new cert to this location:" + "\r\n{1}", id.SubjectName, id.StorePath); throw ServiceResultException.Create(StatusCodes.BadConfigurationError, message); } } else { // ensure it is trusted. await AddToTrustedStore(configuration, certificate); } // add to discovery server. if (configuration.ApplicationType == ApplicationType.Server || configuration.ApplicationType == ApplicationType.ClientAndServer) { try { await AddToDiscoveryServerTrustList(certificate, null, null, configuration.SecurityConfiguration.TrustedPeerCertificates); } catch (Exception e) { Utils.Trace(e, "Could not add certificate to LDS trust list."); } } return true; }
/// <summary> /// Creates an application instance certificate if one does not already exist. /// </summary> public static X509Certificate2 CheckApplicationInstanceCertificate( ApplicationConfiguration configuration, ushort keySize, bool interactive, bool updateFile) { // create a default certificate id none specified. CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate; if (id == null) { id = new CertificateIdentifier(); id.StoreType = Utils.DefaultStoreType; id.StorePath = Utils.DefaultStorePath; id.SubjectName = configuration.ApplicationName; } bool createNewCertificate = false; IList <string> serverDomainNames = configuration.GetServerDomainNames(); // check for private key. X509Certificate2 certificate = id.Find(true); if (certificate == null) { // check if config file has wrong thumprint. if (!String.IsNullOrEmpty(id.SubjectName) && !String.IsNullOrEmpty(id.Thumbprint)) { CertificateIdentifier id2 = new CertificateIdentifier(); id2.StoreType = id.StoreType; id2.StorePath = id.StorePath; id2.SubjectName = id.SubjectName; id = id2; certificate = id2.Find(true); if (certificate != null) { string message = Utils.Format( "Matching certificate with SubjectName={0} found but with a different thumbprint. Use certificate?", id.SubjectName); if (interactive) { if (MessageBox.Show(message, configuration.ApplicationName, MessageBoxButtons.YesNo) == DialogResult.No) { certificate = null; } } } } } // check if private key is missing. if (certificate == null) { certificate = id.Find(false); if (certificate != null) { string message = Utils.Format( "Matching certificate with SubjectName={0} found but without a private key. Create a new certificate?", id.SubjectName); if (interactive) { if (MessageBox.Show(message, configuration.ApplicationName, MessageBoxButtons.YesNo) == DialogResult.No) { certificate = null; } } } } // check domains. if (certificate != null) { IList <string> certificateDomainNames = Utils.GetDomainsFromCertficate(certificate); for (int ii = 0; ii < serverDomainNames.Count; ii++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, serverDomainNames[ii])) { continue; } if (String.Compare(serverDomainNames[ii], "localhost", StringComparison.OrdinalIgnoreCase) == 0) { // check computer name. string computerName = System.Net.Dns.GetHostName(); if (Utils.FindStringIgnoreCase(certificateDomainNames, computerName)) { continue; } // check for aliases. System.Net.IPHostEntry entry = System.Net.Dns.GetHostEntry(computerName); bool found = false; for (int jj = 0; jj < entry.Aliases.Length; jj++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, entry.Aliases[jj])) { found = true; break; } } if (found) { continue; } // check for ip addresses. for (int jj = 0; jj < entry.AddressList.Length; jj++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, entry.AddressList[jj].ToString())) { found = true; break; } } if (found) { continue; } } string message = Utils.Format( "The server is configured to use domain '{0}' which does not appear in the certificate. Update certificate?", serverDomainNames[ii]); createNewCertificate = true; if (interactive) { if (MessageBox.Show(message, configuration.ApplicationName, MessageBoxButtons.YesNo) != DialogResult.Yes) { createNewCertificate = false; continue; } } Utils.Trace(message); break; } if (!createNewCertificate) { // check if key size matches. if (keySize == certificate.PublicKey.Key.KeySize) { AddToTrustedStore(configuration, certificate); return(certificate); } } } // prompt user. if (interactive) { if (!createNewCertificate) { if (MessageBox.Show("Application does not have an instance certificate. Create one automatically?", configuration.ApplicationName, MessageBoxButtons.YesNo) == DialogResult.No) { return(null); } } } // delete existing certificate. if (certificate != null) { DeleteApplicationInstanceCertificate(configuration); } // add the localhost. if (serverDomainNames.Count == 0) { serverDomainNames.Add(System.Net.Dns.GetHostName()); } certificate = Opc.Ua.CertificateFactory.CreateCertificate( id.StoreType, id.StorePath, configuration.ApplicationUri, configuration.ApplicationName, null, serverDomainNames, keySize, 300); id.Certificate = certificate; AddToTrustedStore(configuration, certificate); if (updateFile && !String.IsNullOrEmpty(configuration.SourceFilePath)) { configuration.SaveToFile(configuration.SourceFilePath); } configuration.CertificateValidator.Update(configuration.SecurityConfiguration); return(configuration.SecurityConfiguration.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 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); } } } }
private async void CertificateRequestTimer_Tick(object sender, EventArgs e) { try { NodeId requestId = NodeId.Parse(m_application.CertificateRequestId); byte[] privateKeyPFX = null; byte[][] issuerCertificates = null; byte[] certificate = m_gds.FinishRequest( m_application.ApplicationId, requestId, out privateKeyPFX, out issuerCertificates); if (certificate == null) { // request not done yet, try again in a few seconds return; } CertificateRequestTimer.Enabled = false; RequestProgressLabel.Visible = false; if (m_application.RegistrationType != RegistrationType.ServerPush) { X509Certificate2 newCert = new X509Certificate2(certificate); if (!String.IsNullOrEmpty(m_application.CertificateStorePath) && !String.IsNullOrEmpty(m_application.CertificateSubjectName)) { CertificateIdentifier cid = new CertificateIdentifier() { StorePath = m_application.CertificateStorePath, StoreType = CertificateStoreIdentifier.DetermineStoreType(m_application.CertificateStorePath), SubjectName = m_application.CertificateSubjectName.Replace("localhost", Utils.GetHostName()) }; // update store using (var store = CertificateStoreIdentifier.OpenStore(m_application.CertificateStorePath)) { // if we used a CSR, we already have a private key and therefore didn't request one from the GDS // in this case, privateKey is null if (privateKeyPFX == null) { X509Certificate2 oldCertificate = await cid.Find(true); if (oldCertificate != null && oldCertificate.HasPrivateKey) { oldCertificate = await cid.LoadPrivateKey(string.Empty); newCert = CertificateFactory.CreateCertificateWithPrivateKey(newCert, oldCertificate); await store.Delete(oldCertificate.Thumbprint); } else { throw new ServiceResultException("Failed to merge signed certificate with the private key."); } } else { newCert = new X509Certificate2(privateKeyPFX, string.Empty, X509KeyStorageFlags.Exportable); newCert = CertificateFactory.Load(newCert, true); } await store.Add(newCert); } } else { DialogResult result = DialogResult.Yes; string absoluteCertificatePublicKeyPath = Utils.GetAbsoluteFilePath(m_application.CertificatePublicKeyPath, true, false, false) ?? m_application.CertificatePublicKeyPath; FileInfo file = new FileInfo(absoluteCertificatePublicKeyPath); if (file.Exists) { result = MessageBox.Show( Parent, "Replace certificate " + absoluteCertificatePublicKeyPath + "?", Parent.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); } if (result == DialogResult.Yes) { byte[] exportedCert; if (string.Compare(file.Extension, ".PEM", true) == 0) { exportedCert = CertificateFactory.ExportCertificateAsPEM(newCert); } else { exportedCert = newCert.Export(X509ContentType.Cert); } File.WriteAllBytes(absoluteCertificatePublicKeyPath, exportedCert); } // if we provided a PFX or P12 with the private key, we need to merge the new cert with the private key if (m_application.GetPrivateKeyFormat(m_server?.GetSupportedKeyFormats()) == "PFX") { string absoluteCertificatePrivateKeyPath = Utils.GetAbsoluteFilePath(m_application.CertificatePrivateKeyPath, true, false, false) ?? m_application.CertificatePrivateKeyPath; file = new FileInfo(absoluteCertificatePrivateKeyPath); if (file.Exists) { result = MessageBox.Show( Parent, "Replace private key " + absoluteCertificatePrivateKeyPath + "?", Parent.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); } if (result == DialogResult.Yes) { if (file.Exists) { byte[] pkcsData = File.ReadAllBytes(absoluteCertificatePrivateKeyPath); X509Certificate2 oldCertificate = CertificateFactory.CreateCertificateFromPKCS12(pkcsData, m_certificatePassword); newCert = CertificateFactory.CreateCertificateWithPrivateKey(newCert, oldCertificate); pkcsData = newCert.Export(X509ContentType.Pfx, m_certificatePassword); File.WriteAllBytes(absoluteCertificatePrivateKeyPath, pkcsData); if (privateKeyPFX != null) { throw new ServiceResultException("Did not expect a private key for this operation."); } } else { File.WriteAllBytes(absoluteCertificatePrivateKeyPath, privateKeyPFX); } } } } // update trust list. if (!String.IsNullOrEmpty(m_application.TrustListStorePath)) { using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(m_application.TrustListStorePath)) { foreach (byte[] issuerCertificate in issuerCertificates) { X509Certificate2 x509 = new X509Certificate2(issuerCertificate); X509Certificate2Collection certs = await store.FindByThumbprint(x509.Thumbprint); if (certs.Count == 0) { await store.Add(new X509Certificate2(issuerCertificate)); } } } } m_certificate = newCert; } else { if (privateKeyPFX != null && privateKeyPFX.Length > 0) { var x509 = new X509Certificate2(privateKeyPFX, m_certificatePassword, X509KeyStorageFlags.Exportable); privateKeyPFX = x509.Export(X509ContentType.Pfx); } bool applyChanges = m_server.UpdateCertificate( null, m_server.ApplicationCertificateType, certificate, (privateKeyPFX != null) ? "PFX" : null, privateKeyPFX, issuerCertificates); if (applyChanges) { MessageBox.Show( Parent, "The certificate was updated, however, the apply changes command must be sent before the server will use the new certificate.", Parent.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); ApplyChangesButton.Enabled = true; } } CertificateControl.ShowValue(null, "Application Certificate", new CertificateWrapper() { Certificate = m_certificate }, true); } catch (Exception exception) { if (exception is ServiceResultException sre && sre.StatusCode == StatusCodes.BadNothingToDo) { return; } RequestProgressLabel.Visible = false; CertificateRequestTimer.Enabled = false; Opc.Ua.Client.Controls.ExceptionDlg.Show(Text, exception); } }
/// <summary> /// Initializes the validator from the configuration for a token policy. /// </summary> /// <param name="issuerCertificate">The issuer certificate.</param> private SecurityTokenResolver CreateSecurityTokenResolver(CertificateIdentifier issuerCertificate) { if (issuerCertificate == null) { throw new ArgumentNullException("issuerCertificate"); } // find the certificate. X509Certificate2 certificate = issuerCertificate.Find(false); if (certificate == null) { throw ServiceResultException.Create( StatusCodes.BadCertificateInvalid, "Could not find issuer certificate: {0}", issuerCertificate); } // create a security token representing the certificate. List<SecurityToken> tokens = new List<SecurityToken>(); tokens.Add(new X509SecurityToken(certificate)); // create issued token resolver. SecurityTokenResolver tokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver( new System.Collections.ObjectModel.ReadOnlyCollection<SecurityToken>(tokens), false); return tokenResolver; }
/// <summary> /// Creates a SAML token for the specified email address. /// </summary> public static async System.Threading.Tasks.Task <UserIdentity> CreateSAMLTokenAsync(string emailAddress) { // Normally this would be done by a server that is capable of verifying that // the user is a legimate holder of email address. Using a local certficate to // signed the SAML token is a short cut that would never be done in a real system. CertificateIdentifier userid = new CertificateIdentifier(); userid.StoreType = CertificateStoreType.X509Store; userid.StorePath = "LocalMachine\\My"; userid.SubjectName = "UA Sample Client"; X509Certificate2 certificate = await userid.Find(); X509SecurityToken signingToken = new X509SecurityToken(certificate); // Create list of confirmation strings List <string> confirmations = new List <string>(); // Add holder-of-key string to list of confirmation strings confirmations.Add("urn:oasis:names:tc:SAML:1.0:cm:bearer"); // Create SAML subject statement based on issuer member variable, confirmation string collection // local variable and proof key identifier parameter SamlSubject subject = new SamlSubject("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", null, emailAddress); // Create a list of SAML attributes List <SamlAttribute> attributes = new List <SamlAttribute>(); Claim claim = Claim.CreateNameClaim(emailAddress); attributes.Add(new SamlAttribute(claim)); // Create list of SAML statements List <SamlStatement> statements = new List <SamlStatement>(); // Add a SAML attribute statement to the list of statements. Attribute statement is based on // subject statement and SAML attributes resulting from claims statements.Add(new SamlAttributeStatement(subject, attributes)); // Create a valid from/until condition DateTime validFrom = DateTime.UtcNow; DateTime validTo = DateTime.UtcNow.AddHours(12); SamlConditions conditions = new SamlConditions(validFrom, validTo); // Create the SAML assertion SamlAssertion assertion = new SamlAssertion( "_" + Guid.NewGuid().ToString(), signingToken.Certificate.Subject, validFrom, conditions, null, statements); SecurityKey signingKey = new System.IdentityModel.Tokens.RsaSecurityKey((RSA)signingToken.Certificate.PrivateKey); // Set the signing credentials for the SAML assertion assertion.SigningCredentials = new SigningCredentials( signingKey, System.IdentityModel.Tokens.SecurityAlgorithms.RsaSha1Signature, System.IdentityModel.Tokens.SecurityAlgorithms.Sha1Digest, new SecurityKeyIdentifier(signingToken.CreateKeyIdentifierClause <X509ThumbprintKeyIdentifierClause>())); // TODO // return new UserIdentity(new SamlSecurityToken(assertion)); throw new NotImplementedException(); }
private async void CertificateRequestTimer_Tick(object sender, EventArgs e) { try { NodeId requestId = NodeId.Parse(m_application.CertificateRequestId); byte[] privateKey = null; byte[][] issuerCertificates = null; byte[] certificate = m_gds.FinishRequest( m_application.ApplicationId, requestId, out privateKey, out issuerCertificates); if (certificate == null) { return; } CertificateRequestTimer.Enabled = false; RequestProgressLabel.Visible = false; if (m_application.RegistrationType != RegistrationType.ServerPush) { // save public key. if (!String.IsNullOrEmpty(m_application.CertificatePublicKeyPath)) { string file = Utils.GetAbsoluteFilePath(m_application.CertificatePublicKeyPath, true, false, true); File.WriteAllBytes(file, certificate); } // check if the private was re-used. if (privateKey == null || privateKey.Length == 0) { if (!String.IsNullOrEmpty(m_application.CertificatePrivateKeyPath)) { string path = Utils.GetAbsoluteFilePath(m_application.CertificatePrivateKeyPath, true, true, true); if (path != null) { if (!m_application.CertificatePrivateKeyPath.EndsWith("PEM", StringComparison.OrdinalIgnoreCase)) { var x509 = new X509Certificate2(certificate); var oldPfx = new X509Certificate2(path, (string)null, X509KeyStorageFlags.Exportable); var newPfx = CertificateAuthority.Replace(x509, oldPfx); var bytes = newPfx.Export(X509ContentType.Pfx); File.WriteAllBytes(path, bytes); } } } else { if (!String.IsNullOrEmpty(m_application.CertificateStorePath) && !String.IsNullOrEmpty(m_application.CertificateSubjectName)) { var x509 = new X509Certificate2(certificate); var cid = new CertificateIdentifier() { StorePath = m_application.CertificateStorePath, SubjectName = m_application.CertificateSubjectName.Replace("localhost", System.Net.Dns.GetHostName()) }; var oldPfx = await cid.Find(true); if (oldPfx != null) { var newPfx = CertificateAuthority.Replace(x509, oldPfx); using (var store = CertificateStoreIdentifier.OpenStore(m_application.CertificateStorePath)) { await store.Delete(oldPfx.Thumbprint); await store.Add(newPfx); } } } } } // save private key. else { if (!String.IsNullOrEmpty(m_application.CertificatePrivateKeyPath)) { string path = Utils.GetAbsoluteFilePath(m_application.CertificatePrivateKeyPath, true, true, true); if (path != null) { File.WriteAllBytes(path, privateKey); } } else { if (!String.IsNullOrEmpty(m_application.CertificateStorePath) && !String.IsNullOrEmpty(m_application.CertificateSubjectName)) { var cid = new CertificateIdentifier() { StorePath = m_application.CertificateStorePath, SubjectName = m_application.CertificateSubjectName }; var oldCertificate = await cid.Find(); using (var store = CertificateStoreIdentifier.OpenStore(m_application.CertificateStorePath)) { if (oldCertificate != null) { await store.Delete(oldCertificate.Thumbprint); } var x509 = new X509Certificate2(privateKey, new System.Security.SecureString(), X509KeyStorageFlags.Exportable); x509 = CertificateFactory.Load(x509, true); await store.Add(x509); } } } } // update trust list. if (!String.IsNullOrEmpty(m_application.TrustListStorePath)) { using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(m_application.TrustListStorePath)) { foreach (var issuerCertificate in issuerCertificates) { var x509 = new X509Certificate2(issuerCertificate); if (store.FindByThumbprint(x509.Thumbprint) == null) { await store.Add(new X509Certificate2(issuerCertificate)); } } } } } else { if (privateKey != null && privateKey.Length > 0) { var x509 = new X509Certificate2(privateKey, m_certificatePassword, X509KeyStorageFlags.Exportable); privateKey = x509.Export(X509ContentType.Pfx); } bool applyChanges = m_server.UpdateCertificate(null, null, certificate, GetPrivateKeyFormat(), privateKey, issuerCertificates); if (applyChanges) { MessageBox.Show( Parent, "The certificate was updated, however, the apply changes command must be sent before the server will use the new certificate.", Parent.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); ApplyChangesButton.Enabled = true; } } m_certificate = new X509Certificate2(certificate); CertificateControl.ShowValue(null, "Application Certificate", new CertificateWrapper() { Certificate = m_certificate }, true); } catch (Exception exception) { var sre = exception as ServiceResultException; if (sre != null && sre.StatusCode == StatusCodes.BadNothingToDo) { return; } MessageBox.Show(Parent.Text + ": " + exception.Message); CertificateRequestTimer.Enabled = false; } }
private void RequestNewButton_Click(object sender, EventArgs e) { try { NodeId requestId = null; bool newPrivateKeyRequired = false; if (!String.IsNullOrEmpty(m_application.CertificatePrivateKeyPath)) { string path = Utils.GetAbsoluteFilePath(m_application.CertificatePrivateKeyPath, true, false, false); newPrivateKeyRequired = path == null; } else if (!String.IsNullOrEmpty(m_application.CertificateStorePath)) { CertificateIdentifier id = new CertificateIdentifier(); id.StoreType = CertificateStoreIdentifier.DetermineStoreType(m_application.CertificateStorePath); id.StorePath = m_application.CertificateStorePath; id.SubjectName = m_application.CertificateSubjectName.Replace("localhost", System.Net.Dns.GetHostName()); newPrivateKeyRequired = id.Find(true) == null; } else if (!String.IsNullOrEmpty(m_application.ServerUrl)) { newPrivateKeyRequired = true; } byte[] certificateRequest = null; if (m_application.RegistrationType == RegistrationType.ServerPush) { byte[] nonce = new byte[32]; System.Security.Cryptography.RandomNumberGenerator.Create().GetBytes(nonce); certificateRequest = m_server.CreateCertificateRequest(null, null, null, false, nonce); newPrivateKeyRequired = false; if (m_server.Endpoint != null && m_server.Endpoint.Description.ServerCertificate != null) { m_certificate = new X509Certificate2(m_server.Endpoint.Description.ServerCertificate); } } if (newPrivateKeyRequired || RequestNewPrivateKey || m_certificate == null) { m_certificatePassword = null; // Guid.NewGuid().ToString(); string privateKeyFormat = GetPrivateKeyFormat(); string[] domainNames = GetDomainNames(); string subjectName = GetSubjectName(domainNames); requestId = m_gds.StartNewKeyPairRequest( m_application.ApplicationId, null, null, subjectName, domainNames, privateKeyFormat, m_certificatePassword); } else { if (certificateRequest == null) { var certificate = m_certificate; byte[] privateKey = null; bool isPemKey = false; if (!certificate.HasPrivateKey) { if (!String.IsNullOrEmpty(m_application.CertificatePrivateKeyPath)) { string path = Utils.GetAbsoluteFilePath(m_application.CertificatePrivateKeyPath, true, false, false); if (path != null) { privateKey = File.ReadAllBytes(path); isPemKey = path.EndsWith("PEM", StringComparison.OrdinalIgnoreCase); } } } certificateRequest = CertificateAuthority.CreateRequest( certificate, privateKey, isPemKey, null, null, null, null, 256); } requestId = m_gds.StartSigningRequest(m_application.ApplicationId, null, null, certificateRequest); } m_application.CertificateRequestId = requestId.ToString(); CertificateRequestTimer.Enabled = true; RequestProgressLabel.Visible = true; WarningLabel.Visible = false; } catch (Exception exception) { MessageBox.Show(Parent.Text + ": " + exception.Message); } }
/// <summary> /// Displays the dialog. /// </summary> public bool ShowDialog(CertificateIdentifier certificate) { m_certificate = certificate; CertificateStoreCTRL.StoreType = null; CertificateStoreCTRL.StorePath = null; CertificateStoreCTRL.ReadOnly = true; ApplicationNameTB.Text = null; ApplicationUriTB.Text = null; OrganizationTB.Text = null; DomainsTB.Text = System.Net.Dns.GetHostName(); SubjectNameTB.Text = null; IssuerNameTB.Text = null; ValidFromTB.Text = null; ValidToTB.Text = null; ThumbprintTB.Text = null; if (certificate != null) { CertificateStoreCTRL.StoreType = certificate.StoreType; CertificateStoreCTRL.StorePath = certificate.StorePath; SubjectNameTB.Text = certificate.SubjectName; ThumbprintTB.Text = certificate.Thumbprint; X509Certificate2 data = certificate.Find(); if (data != null) { // fill in subject name. StringBuilder buffer = new StringBuilder(); foreach (string element in Utils.ParseDistinguishedName(data.Subject)) { if (element.StartsWith("CN=")) { ApplicationNameTB.Text = element.Substring(3); } if (element.StartsWith("O=")) { OrganizationTB.Text = element.Substring(2); } if (buffer.Length > 0) { buffer.Append('/'); } buffer.Append(element); } if (buffer.Length > 0) { SubjectNameTB.Text = buffer.ToString(); } // fill in issuer name. buffer = new StringBuilder(); foreach (string element in Utils.ParseDistinguishedName(data.Issuer)) { if (buffer.Length > 0) { buffer.Append('/'); } buffer.Append(element); } if (buffer.Length > 0) { IssuerNameTB.Text = buffer.ToString(); } // fill in application uri. string applicationUri = Utils.GetApplicationUriFromCertficate(data); if (!String.IsNullOrEmpty(applicationUri)) { ApplicationUriTB.Text = applicationUri; } // fill in domains. buffer = new StringBuilder(); foreach (string domain in Utils.GetDomainsFromCertficate(data)) { if (buffer.Length > 0) { buffer.Append(", "); } buffer.Append(domain); } if (buffer.Length > 0) { DomainsTB.Text = buffer.ToString(); } ValidFromTB.Text = data.NotBefore.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); ValidToTB.Text = data.NotAfter.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); ThumbprintTB.Text = data.Thumbprint; } } if (ShowDialog() != DialogResult.OK) { return(false); } return(true); }
private void ExportBTN_Click(object sender, EventArgs e) { try { const string caption = "Export Certificate"; if (m_currentDirectory == null) { m_currentDirectory = Utils.GetAbsoluteDirectoryPath("%LocalApplicationData%", false, false, false); } if (m_currentDirectory == null) { m_currentDirectory = Environment.CurrentDirectory; } X509Certificate2 certificate = m_certificate.Find(); if (certificate == null) { MessageBox.Show("Cannot export an invalid certificate.", caption, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } string displayName = null; foreach (string element in Utils.ParseDistinguishedName(certificate.Subject)) { if (element.StartsWith("CN=")) { displayName = element.Substring(3); break; } } StringBuilder filePath = new StringBuilder(); if (!String.IsNullOrEmpty(displayName)) { filePath.Append(displayName); filePath.Append(" "); } filePath.Append("["); filePath.Append(certificate.Thumbprint); filePath.Append("].der"); SaveFileDialog dialog = new SaveFileDialog(); dialog.CheckFileExists = false; dialog.CheckPathExists = true; dialog.DefaultExt = ".der"; dialog.Filter = "Certificate Files (*.der)|*.der|All Files (*.*)|*.*"; dialog.ValidateNames = true; dialog.Title = "Save Certificate File"; dialog.FileName = filePath.ToString(); dialog.InitialDirectory = m_currentDirectory; if (dialog.ShowDialog() != DialogResult.OK) { return; } FileInfo fileInfo = new FileInfo(dialog.FileName); m_currentDirectory = fileInfo.DirectoryName; // save the file. using (Stream ostrm = fileInfo.Open(FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { byte[] data = certificate.RawData; ostrm.Write(data, 0, data.Length); } } catch (Exception exception) { GuiUtils.HandleException(this.Text, System.Reflection.MethodBase.GetCurrentMethod(), exception); } }
private void OkBTN_Click(object sender, EventArgs e) { try { IPAddress address = IPAddress.Parse(IPAddressTB.Text); ushort port = (ushort)PortUD.Value; if (m_certificate == null) { throw new ArgumentException("You must specify a certificate."); } X509Certificate2 certificate = m_certificate.Find(true); if (certificate == null) { throw new ArgumentException("Certificate does not exist or has no private key."); } // setup policy chain X509ChainPolicy policy = new X509ChainPolicy(); policy.RevocationFlag = X509RevocationFlag.EntireChain; policy.RevocationMode = X509RevocationMode.Offline; policy.VerificationFlags = X509VerificationFlags.NoFlag; policy.VerificationFlags |= X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown; policy.VerificationFlags |= X509VerificationFlags.IgnoreCtlSignerRevocationUnknown; policy.VerificationFlags |= X509VerificationFlags.IgnoreEndRevocationUnknown; policy.VerificationFlags |= X509VerificationFlags.IgnoreRootRevocationUnknown; // build chain. X509Chain chain = new X509Chain(); chain.ChainPolicy = policy; chain.Build(certificate); for (int ii = 0; ii < chain.ChainElements.Count; ii++) { X509ChainElement element = chain.ChainElements[ii]; // check for chain status errors. foreach (X509ChainStatus status in element.ChainElementStatus) { if (status.Status == X509ChainStatusFlags.UntrustedRoot) { if (!Ask("Cannot verify certificate up to a trusted root.\r\nAdd anyways?")) { return; } continue; } if (status.Status == X509ChainStatusFlags.RevocationStatusUnknown) { if (!Ask("The revocation status of this certificate cannot be verified.\r\nAdd anyways?")) { return; } continue; } // ignore informational messages. if (status.Status == X509ChainStatusFlags.OfflineRevocation) { continue; } if (status.Status != X509ChainStatusFlags.NoError) { throw new ArgumentException("[" + status.Status + "] " + status.StatusInformation); } } } // get the target store. if (m_store == null) { m_store = new CertificateStoreIdentifier(); m_store.StoreType = CertificateStoreType.Windows; m_store.StorePath = CertificateStoreTB.Text; } if (m_store.StoreType != CertificateStoreType.Windows) { throw new ArgumentException("You must choose a Windows store for SSL certificates."); } if (!m_store.StorePath.StartsWith("LocalMachine\\", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException("You must choose a machine store for SSL certificates."); } bool deleteExisting = false; using (ICertificateStore store = m_store.OpenStore()) { if (store.FindByThumbprint(certificate.Thumbprint) == null) { store.Add(certificate); deleteExisting = true; } } if (deleteExisting) { if (Ask("Would you like to delete the certificate from its current location?")) { using (ICertificateStore store = m_certificate.OpenStore()) { store.Delete(certificate.Thumbprint); } } } SslCertificateBinding binding = new SslCertificateBinding(); binding.IPAddress = address; binding.Port = port; binding.Thumbprint = certificate.Thumbprint; binding.ApplicationId = s_DefaultApplicationId; binding.StoreName = null; if (!m_store.StorePath.EndsWith("\\My")) { int index = m_store.StorePath.LastIndexOf("\\"); binding.StoreName = m_store.StorePath.Substring(index + 1); } HttpAccessRule.SetSslCertificateBinding(binding); m_binding = binding; DialogResult = DialogResult.OK; } catch (Exception exception) { GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception); } }
public static EndpointDescription CreateEndpointDescription(UAServer myServer) { // create the endpoint description. EndpointDescription endpointDescription = null; try { string discoveryUrl = myServer.ServerName; //OA 2018-04-27 if (!discoveryUrl.StartsWith(Utils.UriSchemeOpcTcp) && !discoveryUrl.StartsWith(Utils.UriSchemeHttps)) //if (!discoveryUrl.StartsWith(Utils.UriSchemeOpcTcp)) { if (!discoveryUrl.EndsWith("/discovery")) { discoveryUrl += "/discovery"; } } // parse the selected URL. Uri uri = new Uri(discoveryUrl); // set a short timeout because this is happening in the drop down event. EndpointConfiguration configuration = EndpointConfiguration.Create(); configuration.OperationTimeout = 5000; //OA 2018-04-27 https if (discoveryUrl.StartsWith(Utils.UriSchemeHttps)) { configuration.OperationTimeout = 0; } // // Connect to the server's discovery endpoint and find the available configuration. using (DiscoveryClient client = DiscoveryClient.Create(uri, configuration)) { EndpointDescriptionCollection endpoints = client.GetEndpoints(null); // select the best endpoint to use based on the selected URL and the UseSecurity checkbox. for (int ii = 0; ii < endpoints.Count; ii++) { EndpointDescription endpoint = endpoints[ii]; // check for a match on the URL scheme. if (endpoint.EndpointUrl.StartsWith(uri.Scheme)) { // check if security was requested. if (!myServer.SecurityPolicy.Equals("None")) { if (endpoint.SecurityMode == MessageSecurityMode.None) { continue; } } else { if (endpoint.SecurityMode != MessageSecurityMode.None) { continue; } } // pick the first available endpoint by default. if (endpointDescription == null) { endpointDescription = endpoint; } // The security level is a relative measure assigned by the server to the // endpoints that it returns. Clients should always pick the highest level // unless they have a reason not too. if (endpoint.SecurityLevel > endpointDescription.SecurityLevel) { endpointDescription = endpoint; } } } // pick the first available endpoint by default. if (endpointDescription == null && endpoints.Count > 0) { endpointDescription = endpoints[0]; } } // if a server is behind a firewall it may return URLs that are not accessible to the client. // This problem can be avoided by assuming that the domain in the URL used to call // GetEndpoints can be used to access any of the endpoints. This code makes that conversion. // Note that the conversion only makes sense if discovery uses the same protocol as the endpoint. Uri endpointUrl = Utils.ParseUri(endpointDescription.EndpointUrl); if (endpointUrl != null && endpointUrl.Scheme == uri.Scheme) { UriBuilder builder = new UriBuilder(endpointUrl); builder.Host = uri.DnsSafeHost; builder.Port = uri.Port; endpointDescription.EndpointUrl = builder.ToString(); } } catch { endpointDescription = new EndpointDescription(); endpointDescription.EndpointUrl = myServer.ServerName; //ABA 2014-10-10 if (myServer.SecurityPolicy.Equals("None")) { endpointDescription.SecurityPolicyUri = SecurityPolicies.None; } //Commented by MM 03/07/2019 //else if (myServer.SecurityPolicy.Equals("Basic128Rsa15")) //{ // endpointDescription.SecurityPolicyUri = SecurityPolicies.Basic128Rsa15; //} else if (myServer.SecurityPolicy.Equals("Basic256Sha256")) { endpointDescription.SecurityPolicyUri = SecurityPolicies.Basic256Sha256; } else if (myServer.SecurityPolicy.Equals("Basic256")) { endpointDescription.SecurityPolicyUri = SecurityPolicies.Basic256; } try { MessageSecurityMode myMode; myMode = (MessageSecurityMode)Enum.Parse(typeof(MessageSecurityMode), myServer.SecurityMode, false); //endpointDescription.SecurityMode = MessageSecurityMode.SignAndEncrypt; endpointDescription.SecurityMode = myMode; } catch { endpointDescription.SecurityMode = MessageSecurityMode.None; } // specify the transport profile. if (myServer.Protocol.Equals("opc.tcp")) { endpointDescription.TransportProfileUri = Profiles.UaTcpTransport; } //added OA 2018-04-27 else if (myServer.Protocol.Equals("http")) { //OA-2018-06-18 endpointDescription.TransportProfileUri = Profiles.WsHttpXmlOrBinaryTransport; } else //added OA 2018-04-27 { endpointDescription.TransportProfileUri = Profiles.HttpsBinaryTransport; //OA-2018-06-18 HttpsXmlOrBinaryTransport; } //else //OA 2018-04-27 //{ // endpointDescription.TransportProfileUri = Profiles.WsHttpXmlOrBinaryTransport; //} if (myServer.UserIdentity.Equals(UserIdentityType.Certificate)) { // load the the server certificate from the local certificate store. CertificateIdentifier certificateIdentifier = new CertificateIdentifier(); certificateIdentifier.StoreType = CertificateStoreType.X509Store; //OA-2018-06-18 .Windows; if (!String.IsNullOrEmpty(myServer.CertificationStore)) { //certificateIdentifier.StorePath = "LocalMachine\\UA Applications"; certificateIdentifier.StorePath = myServer.CertificationStore; } else { using (System.IO.FileStream fs = System.IO.File.OpenRead(myServer.CertificationPath)) { byte[] bytes = new byte[fs.Length]; fs.Read(bytes, 0, Convert.ToInt32(fs.Length)); certificateIdentifier.RawData = bytes; } } //certificateIdentifier.SubjectName = "ONBServer";//commented by HHA 12/11//2019 //OA-2018-06-25 //X509Certificate2 serverCertificate = certificateIdentifier.Find(); X509Certificate2 serverCertificate = certificateIdentifier.Find().Result; if (serverCertificate == null) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "Could not find server certificate: {0}", certificateIdentifier.SubjectName); } endpointDescription.ServerCertificate = serverCertificate.GetRawCertData(); } } return(endpointDescription); }
/// <summary> /// Initialize the OPC UA Application's security configuration /// </summary> /// <returns></returns> private async Task InitApplicationSecurityAsync() { // update certificates validator _opcApplicationConfig.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(VerifyCertificate); await _opcApplicationConfig.CertificateValidator .Update(_opcApplicationConfig).ConfigureAwait(false); // lookup for an existing certificate in the configured store var ownCertificate = await _opcApplicationConfig.SecurityConfiguration .ApplicationCertificate.Find(true).ConfigureAwait(false); if (ownCertificate == null) { // // Work around windows issue and lookup application certificate also on // directory if configured. This is needed for container persistence. // if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _configuration.AppCertStoreType == CertificateStoreType.Directory) { // Use x509 store instead of directory for private cert. var ownCertificateIdentifier = new CertificateIdentifier { StoreType = _configuration.AppCertStoreType, StorePath = _configuration.OwnCertPath, SubjectName = _opcApplicationConfig.SecurityConfiguration .ApplicationCertificate.SubjectName }; ownCertificate = await ownCertificateIdentifier.Find(true) .ConfigureAwait(false); if ((ownCertificate != null) && !ownCertificate.Verify()) { try { _logger.Warning("Found malformed own certificate {Thumbprint}, " + "{Subject} in the store - deleting it...", ownCertificate.Thumbprint, ownCertificate.Subject); ownCertificateIdentifier.RemoveFromStore(ownCertificate); } catch (Exception ex) { _logger.Information(ex, "Failed to remove malformed own certificate"); } ownCertificate = null; } } } if (ownCertificate == null) { _logger.Information("Application own certificate not found. " + "Creating a new self-signed certificate with default settings..."); ownCertificate = CertificateFactory.CreateCertificate( _opcApplicationConfig.SecurityConfiguration.ApplicationCertificate.StoreType, _opcApplicationConfig.SecurityConfiguration.ApplicationCertificate.StorePath, null, _opcApplicationConfig.ApplicationUri, _opcApplicationConfig.ApplicationName, _opcApplicationConfig.SecurityConfiguration.ApplicationCertificate.SubjectName, null, CertificateFactory.defaultKeySize, DateTime.UtcNow - TimeSpan.FromDays(1), CertificateFactory.defaultLifeTime, CertificateFactory.defaultHashSize, false, null, null); _opcApplicationConfig.SecurityConfiguration.ApplicationCertificate.Certificate = ownCertificate; _logger.Information( "New application certificate with {Thumbprint}, {Subject} created", ownCertificate.Thumbprint, ownCertificate.SubjectName.Name); } else { _logger.Information("Application certificate with {Thumbprint}, {Subject} " + "found in the certificate store", ownCertificate.Thumbprint, ownCertificate.SubjectName.Name); } // Set the Certificate as the newly created certificate await SetOwnCertificateAsync(ownCertificate); if (_opcApplicationConfig.SecurityConfiguration.AutoAcceptUntrustedCertificates) { _logger.Warning( "WARNING: Automatically accepting certificates. This is a security risk."); } }