private void OnSaveCertificateButtonClick(object?sender, EventArgs e) { Debug.Assert(_LastImportedSignedCertificate != null); string SubjectName = string.IsNullOrWhiteSpace(_CommonNameTextBox.Text) ? "Certificate" : _CommonNameTextBox.Text; using SaveFileDialog SaveFileDialog = new SaveFileDialog { Title = "Save Certificate", FileName = $"{SubjectName}.pfx", Filter = "Certificatess (*.pfx)|*.pfx" }; if (SaveFileDialog.ShowDialog() == DialogResult.OK) { using Stream FileStream = SaveFileDialog.OpenFile(); using BinaryWriter Writer = new BinaryWriter(FileStream); byte[] CertificateData; if (_LastGeneratedRSAPrivateKey != null) { using X509Certificate2 CertificateWithPrivateKey = _LastImportedSignedCertificate.CopyWithPrivateKey(_LastGeneratedRSAPrivateKey); CertificateData = CertificateWithPrivateKey.Export(X509ContentType.Pfx, _CertificatePasswordTextBox.Text); } else { Debug.Assert(_LastGeneratedECDsaPrivateKey != null); using NativeMethods.SafeCertContextHandle certificateContext = NativeMethods.GetCertificateContext(_LastImportedSignedCertificate); using SafeNCryptKeyHandle KeyHandle = _LastGeneratedECDsaPrivateKey.Key.Handle; if (!NativeMethods.CertSetCertificateContextProperty( certificateContext, NativeMethods.CertificateProperty.NCryptKeyHandle, NativeMethods.CertificateSetPropertyFlags.CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, KeyHandle)) { throw new InvalidOperationException($"ECDsa private key could not be set on Certificate Win32Error [{Marshal.GetLastWin32Error()}] returned."); } using X509Certificate2 CertificateWithPrivateKey = new X509Certificate2(certificateContext.DangerousGetHandle()); CertificateData = CertificateWithPrivateKey.Export(X509ContentType.Pfx, _CertificatePasswordTextBox.Text); } Writer.Write(CertificateData); } }
// .NET does not have a way to get an ECC public/private key out of an X509 certificate. Remove this and Certificate NativeMethods if it ever gets one! public static CngKey GetCngPrivateKey(this X509Certificate2 certificate) { if (!certificate.HasPrivateKey) { throw new InvalidOperationException("Certificate does not have a PrivateKey."); } using NativeMethods.SafeCertContextHandle certificateContext = NativeMethods.GetCertificateContext(certificate); SafeNCryptKeyHandle?privateKeyHandle = NativeMethods.TryAcquireCngPrivateKey(certificateContext, out CngKeyHandleOpenOptions openOptions); if (privateKeyHandle == null) { throw new InvalidOperationException("Certificate PrivateKey could not be opened."); } try { return(CngKey.Open(privateKeyHandle, openOptions)); } finally { privateKeyHandle.Dispose(); } }