Example #1
0
        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();
            }
        }