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); } }
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); } }
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; } }