diff --git a/Samples/GDS/Client/Controls/ApplicationCertificateControl.Designer.cs b/Samples/GDS/Client/Controls/ApplicationCertificateControl.Designer.cs index 3710dc1af..8c208f972 100644 --- a/Samples/GDS/Client/Controls/ApplicationCertificateControl.Designer.cs +++ b/Samples/GDS/Client/Controls/ApplicationCertificateControl.Designer.cs @@ -34,6 +34,8 @@ private void InitializeComponent() this.WarningLabel = new System.Windows.Forms.Label(); this.CertificateControl = new Opc.Ua.Gds.Client.Controls.EditValueCtrl(); this.RegistrationButtonsPanel = new System.Windows.Forms.Panel(); + this.PrivateKeyPasswordTextBox = new System.Windows.Forms.TextBox(); + this.PrivateKeyPasswordLabel = new System.Windows.Forms.Label(); this.ApplyChangesButton = new System.Windows.Forms.Button(); this.RequestNewButton = new System.Windows.Forms.Button(); this.CertificateRequestTimer = new System.Windows.Forms.Timer(this.components); @@ -94,6 +96,8 @@ private void InitializeComponent() // RegistrationButtonsPanel // this.RegistrationButtonsPanel.BackColor = System.Drawing.Color.MidnightBlue; + this.RegistrationButtonsPanel.Controls.Add(this.PrivateKeyPasswordTextBox); + this.RegistrationButtonsPanel.Controls.Add(this.PrivateKeyPasswordLabel); this.RegistrationButtonsPanel.Controls.Add(this.ApplyChangesButton); this.RegistrationButtonsPanel.Controls.Add(this.RequestNewButton); this.RegistrationButtonsPanel.Dock = System.Windows.Forms.DockStyle.Bottom; @@ -102,6 +106,27 @@ private void InitializeComponent() this.RegistrationButtonsPanel.Size = new System.Drawing.Size(879, 32); this.RegistrationButtonsPanel.TabIndex = 13; // + // PrivateKeyPasswordLabel + // + this.PrivateKeyPasswordLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.PrivateKeyPasswordLabel.AutoSize = true; + this.PrivateKeyPasswordLabel.ForeColor = System.Drawing.Color.White; + this.PrivateKeyPasswordLabel.Location = new System.Drawing.Point(524, 9); + this.PrivateKeyPasswordLabel.Name = "PrivateKeyPasswordLabel"; + this.PrivateKeyPasswordLabel.Size = new System.Drawing.Size(115, 13); + this.PrivateKeyPasswordLabel.TabIndex = 5; + this.PrivateKeyPasswordLabel.Text = "Private Key Password:"; + // + // PrivateKeyPasswordTextBox + // + this.PrivateKeyPasswordTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.PrivateKeyPasswordTextBox.Location = new System.Drawing.Point(645, 6); + this.PrivateKeyPasswordTextBox.Name = "PrivateKeyPasswordTextBox"; + this.PrivateKeyPasswordTextBox.Size = new System.Drawing.Size(225, 20); + this.PrivateKeyPasswordTextBox.TabIndex = 6; + this.PrivateKeyPasswordTextBox.UseSystemPasswordChar = true; + this.PrivateKeyPasswordTextBox.TextChanged += new System.EventHandler(this.PrivateKeyPasswordTextBox_TextChanged); + // // ApplyChangesButton // this.ApplyChangesButton.BackColor = System.Drawing.Color.MidnightBlue; @@ -163,5 +188,7 @@ private void InitializeComponent() private System.Windows.Forms.Timer CertificateRequestTimer; private System.Windows.Forms.Label RequestProgressLabel; private System.Windows.Forms.Button ApplyChangesButton; + private System.Windows.Forms.Label PrivateKeyPasswordLabel; + private System.Windows.Forms.TextBox PrivateKeyPasswordTextBox; } } diff --git a/Samples/GDS/Client/Controls/ApplicationCertificateControl.cs b/Samples/GDS/Client/Controls/ApplicationCertificateControl.cs index aaae00280..e13e90f13 100644 --- a/Samples/GDS/Client/Controls/ApplicationCertificateControl.cs +++ b/Samples/GDS/Client/Controls/ApplicationCertificateControl.cs @@ -74,6 +74,7 @@ public async Task InitializeAsync( m_certificate = null; m_temporaryCertificateCreated = false; m_certificatePassword = null; + PrivateKeyPasswordTextBox.Text = string.Empty; CertificateRequestTimer.Enabled = false; RequestProgressLabel.Visible = false; @@ -260,9 +261,46 @@ private async Task FindCertificateAsync(CertificateIdentifier return null; } - private Task LoadPrivateKeyAsync(CertificateIdentifier id, X509Certificate2 certificate, char[] password) + private async Task LoadPrivateKeyAsync(CertificateIdentifier id, X509Certificate2 certificate, char[] password) { - return Task.FromResult(certificate); + if (certificate == null) + { + return null; + } + + // Certificate already carries an exportable private key, nothing to load. + if (certificate.HasPrivateKey) + { + return certificate; + } + + if (id == null || String.IsNullOrEmpty(id.StorePath)) + { + return certificate; + } + + var storeIdentifier = new CertificateStoreIdentifier(id.StorePath, false); + using (ICertificateStore store = storeIdentifier.OpenStore(m_telemetry)) + { + if (store == null || !store.SupportsLoadPrivateKey) + { + return certificate; + } + + Certificate withPrivateKey = await store.LoadPrivateKeyAsync( + certificate.Thumbprint, + certificate.Subject, + null, + id.CertificateType, + (password != null && password.Length > 0) ? password : null); + + if (withPrivateKey != null) + { + return withPrivateKey.AsX509Certificate2(); + } + } + + return certificate; } private async Task RequestNewCertificatePullModeAsync(object sender, EventArgs e) { @@ -410,7 +448,7 @@ private async void CertificateRequestTimer_Tick(object sender, EventArgs e) X509Certificate2 oldCertificate = await FindCertificateAsync(cid); if (oldCertificate != null && oldCertificate.HasPrivateKey) { - oldCertificate = await LoadPrivateKeyAsync(cid, oldCertificate, []); + oldCertificate = await LoadPrivateKeyAsync(cid, oldCertificate, m_certificatePassword?.ToCharArray()); newCert = DefaultCertificateFactory.Instance.CreateWithPrivateKey(Certificate.From(newCert), Certificate.From(m_temporaryCertificateCreated ? m_certificate : oldCertificate)).AsX509Certificate2(); await store.DeleteAsync(oldCertificate.Thumbprint); } @@ -421,7 +459,7 @@ private async void CertificateRequestTimer_Tick(object sender, EventArgs e) } else { - newCert = GdsCertificateLoader.LoadPkcs12(privateKeyPFX.ToArray(), string.Empty, X509KeyStorageFlags.Exportable); + newCert = GdsCertificateLoader.LoadPkcs12(privateKeyPFX.ToArray(), m_certificatePassword ?? string.Empty, X509KeyStorageFlags.Exportable); } await store.AddAsync(Certificate.From(newCert)); if (m_temporaryCertificateCreated) @@ -611,5 +649,10 @@ private void Button_MouseLeave(object sender, EventArgs e) ((Control)sender).BackColor = Color.MidnightBlue; } + private void PrivateKeyPasswordTextBox_TextChanged(object sender, EventArgs e) + { + m_certificatePassword = PrivateKeyPasswordTextBox.Text; + } + } }