예제 #1
0
        /// <summary>
        ///   Create a PEM-encoded PKCS#10 CertificationRequest representing the current state
        ///   of this object using the provided signature generator.
        /// </summary>
        /// <param name="signatureGenerator">
        ///   A <see cref="X509SignatureGenerator"/> with which to sign the request.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///   <paramref name="signatureGenerator" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///   <para>
        ///     <see cref="OtherRequestAttributes"/> contains a <see langword="null" /> value.
        ///   </para>
        ///   <para>- or -</para>
        ///   <para>
        ///     <see cref="OtherRequestAttributes"/> contains an entry with a <see langword="null" />
        ///     <see cref="AsnEncodedData.Oid" /> value.
        ///   </para>
        ///   <para>- or -</para>
        ///   <para>
        ///     <see cref="OtherRequestAttributes"/> contains an entry representing the PKCS#9
        ///     Extension Request Attribute (1.2.840.113549.1.9.14).
        ///   </para>
        ///   <para>- or -</para>
        ///   <para>
        ///     <see cref="CertificateExtensions"/> contains a <see langword="null" /> value.
        ///   </para>
        ///   <para>- or -</para>
        ///   <para>
        ///     <see cref="CertificateExtensions"/> contains an entry with a <see langword="null" />
        ///     <see cref="AsnEncodedData.Oid" /> value.
        ///   </para>
        ///   <para>- or -</para>
        ///   <para>
        ///     This object was created with a constructor which did not accept a signing key.
        ///   </para>
        /// </exception>
        /// <exception cref="CryptographicException">
        ///   A cryptographic error occurs while creating the signing request.
        /// </exception>
        /// <seealso cref="CreateSigningRequest(X509SignatureGenerator)"/>
        public string CreateSigningRequestPem(X509SignatureGenerator signatureGenerator)
        {
            ArgumentNullException.ThrowIfNull(signatureGenerator);

            byte[] der = CreateSigningRequest(signatureGenerator);
            return(PemEncoding.WriteString(PemLabels.Pkcs10CertificateRequest, der));
        }
예제 #2
0
        public static unsafe bool TryExportToPem <T>(
            T arg,
            string label,
            TryExportKeyAction <T> exporter,
            Span <char> destination,
            out int charsWritten)
        {
            int bufferSize = 4096;

            while (true)
            {
                byte[] buffer       = CryptoPool.Rent(bufferSize);
                int    bytesWritten = 0;
                bufferSize = buffer.Length;

                // Fixed to prevent GC moves.
                fixed(byte *bufferPtr = buffer)
                {
                    try
                    {
                        if (exporter(arg, buffer, out bytesWritten))
                        {
                            Span <byte> writtenSpan = new Span <byte>(buffer, 0, bytesWritten);
                            return(PemEncoding.TryWrite(label, writtenSpan, destination, out charsWritten));
                        }
                    }
                    finally
                    {
                        CryptoPool.Return(buffer, bytesWritten);
                    }

                    bufferSize = checked (bufferSize * 2);
                }
            }
        }
예제 #3
0
        public static void ImportEncryptedPem <TPass>(
            ReadOnlySpan <char> input,
            ReadOnlySpan <TPass> password,
            ImportEncryptedKeyAction <TPass> importAction)
        {
            bool                foundEncryptedPem = false;
            PemFields           foundFields       = default;
            ReadOnlySpan <char> foundSlice        = default;

            ReadOnlySpan <char> pem = input;

            while (PemEncoding.TryFind(pem, out PemFields fields))
            {
                ReadOnlySpan <char> label = pem[fields.Label];

                if (label.SequenceEqual(PemLabels.EncryptedPkcs8PrivateKey))
                {
                    if (foundEncryptedPem)
                    {
                        throw new ArgumentException(SR.Argument_PemImport_AmbiguousPem, nameof(input));
                    }

                    foundEncryptedPem = true;
                    foundFields       = fields;
                    foundSlice        = pem;
                }

                Index offset = fields.Location.End;
                pem = pem[offset..];
        protected override PemFields FindPem(ReadOnlySpan <char> input)
        {
            bool found = PemEncoding.TryFind(input, out PemFields fields);

            Assert.True(found, "Did not find PEM.");
            return(fields);
        }
        public static string ExportPemEncodedPublicKey(this RSA rsa)
        {
            var keyBytes = rsa.ExportRSAPublicKey();
            var pemChars = PemEncoding.Write(PemEncodingLabels.RsaPublicKey, keyBytes);

            return(new string(pemChars));
        }
예제 #6
0
        public static void Write_Simple()
        {
            string label = "HELLO";

            byte[] content = new byte[] { 0x66, 0x6F, 0x6F };
            char[] result  = PemEncoding.Write(label, content);
            string pem     = new string(result);

            Assert.Equal("-----BEGIN HELLO-----\nZm9v\n-----END HELLO-----", pem);
        }
예제 #7
0
        private static FileInfo CreateBundleFile(string directoryPath, X509Certificate2 certificate)
        {
            FileInfo file = new(Path.Combine(directoryPath, FallbackCertificateBundleX509ChainFactory.FileName));

            char[] pem = PemEncoding.Write("CERTIFICATE", certificate.RawData);

            File.WriteAllText(file.FullName, new string(pem));

            return(file);
        }
예제 #8
0
        public static V1Secret?AsSecret(this PairingRecord?pairingRecord)
        {
            if (pairingRecord == null)
            {
                return(null);
            }

            var secret = new V1Secret()
            {
                ApiVersion = V1Secret.KubeApiVersion,
                Kind       = V1Secret.KubeKind,
                Type       = TlsType,
                Metadata   = new V1ObjectMeta(),
                Data       = new Dictionary <string, byte[]>(),
                Immutable  = true,
            };

            secret.Data[TlsCertificateKey] =
                Encoding.UTF8.GetBytes(
                    PemEncoding.Write(
                        "CERTIFICATE",
                        pairingRecord.HostCertificate.Export(X509ContentType.Cert)));

            secret.Data[TlsPrivateKey] =
                Encoding.UTF8.GetBytes(
                    PemEncoding.Write(
                        "PRIVATE KEY",
                        pairingRecord.HostPrivateKey.ExportPkcs8PrivateKey()));

            secret.Data[CaCertificateKey] =
                Encoding.UTF8.GetBytes(
                    PemEncoding.Write(
                        "CERTIFICATE",
                        pairingRecord.RootCertificate.Export(X509ContentType.Cert)));

            secret.Data[CaPrivateKey] =
                Encoding.UTF8.GetBytes(
                    PemEncoding.Write(
                        "PRIVATE KEY",
                        pairingRecord.RootPrivateKey.ExportPkcs8PrivateKey()));

            secret.Data[DeviceCertificateKey] =
                Encoding.UTF8.GetBytes(
                    PemEncoding.Write(
                        "CERTIFICATE",
                        pairingRecord.DeviceCertificate.Export(X509ContentType.Cert)));

            secret.Data[EscrowBagKey]      = pairingRecord.EscrowBag;
            secret.Data[HostIdKey]         = Encoding.UTF8.GetBytes(pairingRecord.HostId);
            secret.Data[SystemBuidKey]     = Encoding.UTF8.GetBytes(pairingRecord.SystemBUID);
            secret.Data[WifiMacAddressKey] = pairingRecord.WiFiMacAddress == null ? null : Encoding.UTF8.GetBytes(pairingRecord.WiFiMacAddress);

            return(secret);
        }
예제 #9
0
        public string ExportPkcs7Pem()
        {
            byte[]? pkcs7 = Export(X509ContentType.Pkcs7);

            if (pkcs7 is null)
            {
                throw new CryptographicException(SR.Cryptography_X509_ExportFailed);
            }

            return(PemEncoding.WriteString(PemLabels.Pkcs7Certificate, pkcs7));
        }
예제 #10
0
        public static void TryWrite_Simple()
        {
            char[] buffer = new char[1000];
            string label  = "HELLO";

            byte[] content = new byte[] { 0x66, 0x6F, 0x6F };
            Assert.True(PemEncoding.TryWrite(label, content, buffer, out int charsWritten));
            string pem = new string(buffer, 0, charsWritten);

            Assert.Equal("-----BEGIN HELLO-----\nZm9v\n-----END HELLO-----", pem);
        }
예제 #11
0
        public bool TryExportPkcs7Pem(Span <char> destination, out int charsWritten)
        {
            byte[]? pkcs7 = Export(X509ContentType.Pkcs7);

            if (pkcs7 is null)
            {
                throw new CryptographicException(SR.Cryptography_X509_ExportFailed);
            }

            return(PemEncoding.TryWrite(PemLabels.Pkcs7Certificate, pkcs7, destination, out charsWritten));
        }
        /// <summary>
        ///     Exports the private key of the specified certificate using the new .net 6 method
        /// </summary>
        /// <param name="certificate"></param>
        /// <returns></returns>
        private static string ExportPrivateKeyPkcs1Pem(X509Certificate2 certificate)
        {
            RSA rsa = certificate.GetRSAPrivateKey();

            Assert.NotNull(rsa);

            byte[] privateKeyBytes = rsa.ExportRSAPrivateKey();

            char[] privateKeyPem = PemEncoding.Write("RSA PRIVATE KEY", privateKeyBytes);

            return(new string(privateKeyPem));
        }
예제 #13
0
        public string ExportPkcs7Pem()
        {
            byte[]? pkcs7 = Export(X509ContentType.Pkcs7);

            if (pkcs7 is null)
            {
                throw new CryptographicException(SR.Cryptography_X509_ExportFailed);
            }

            int encodedSize = PemEncoding.GetEncodedSize(PemLabels.Pkcs7Certificate.Length, pkcs7.Length);

            return(string.Create(encodedSize, pkcs7, static (destination, pkcs7) => {
예제 #14
0
        public static string GeneratePEMWithPrivateKeyAsString(X509Certificate2 certificate)
        {
            var sb = new StringBuilder();
            AsymmetricAlgorithm key = certificate.GetRSAPrivateKey();

            byte[] privKeyBytes   = key.ExportPkcs8PrivateKey();
            char[] privKeyPem     = PemEncoding.Write("PRIVATE KEY", privKeyBytes);
            char[] certificatePem = PemEncoding.Write("CERTIFICATE", certificate.GetRawCertData());
            sb.AppendLine(new string(privKeyPem));
            sb.AppendLine();
            sb.AppendLine(new string(certificatePem));
            return(sb.ToString());
        }
예제 #15
0
        private static byte[] DecodePemData(ReadOnlySpan <char> pemData)
        {
            PemEncoding.TryFind(pemData, out PemFields fields);

            byte[] decodedData = new byte[fields.DecodedDataLength];

            if (!Convert.TryFromBase64Chars(pemData[fields.Base64Data], decodedData, out _))
            {
                throw new Exception("Error decoding pem data");
            }

            return(decodedData);
        }
예제 #16
0
 public X509Certificate2 GetValidationCert(TransportCustomizations settings)
 {
     try
     {
         var fields     = PemEncoding.Find(settings.TLSValidationCert);
         var base64Data = settings.TLSValidationCert[fields.Base64Data];
         return(new X509Certificate2(Encoding.ASCII.GetBytes(base64Data)));
     }
     catch (Exception e)
     {
         throw new HttpException(HttpStatusCode.BadRequest, $"Unable to instantiate a valid cert from the value provided in Transport settings key \"TLSValidationCert\". Value: \"{settings.TLSValidationCert}\". Message: \"{e.Message}\".");
     }
 }
예제 #17
0
        /// <summary>
        /// Attempts to export the public X.509 certificates, encoded as PEM.
        /// </summary>
        /// <param name="destination">The buffer to receive the PEM encoded certificates.</param>
        /// <param name="charsWritten">When this method returns, the total number of characters written to <paramref name="destination" />.</param>
        /// <returns>
        ///   <see langword="true"/> if <paramref name="destination"/> was large enough to receive the encoded PEMs;
        ///   otherwise, <see langword="false" />.
        /// </returns>
        /// <exception cref="CryptographicException">
        /// A certificate is corrupt, in an invalid state, or could not be exported
        /// to PEM.
        /// </exception>
        /// <remarks>
        /// <p>
        ///   A PEM-encoded X.509 certificate collection will contain certificates
        ///   where each certificate begins with <c>-----BEGIN CERTIFICATE-----</c>
        ///   and ends with <c>-----END CERTIFICATE-----</c>, with the base64 encoded DER
        ///   contents of the certificate between the PEM boundaries. Each certificate is
        ///   separated by a single line-feed character.
        /// </p>
        /// <p>
        ///   Certificates are encoded according to the IETF RFC 7468 &quot;strict&quot;
        ///   encoding rules.
        /// </p>
        /// </remarks>
        public bool TryExportCertificatePems(Span <char> destination, out int charsWritten)
        {
            Span <char> buffer  = destination;
            int         written = 0;

            for (int i = 0; i < Count; i++)
            {
                ReadOnlyMemory <byte> certData = this[i].RawDataMemory;
                int certSize = PemEncoding.GetEncodedSize(PemLabels.X509Certificate.Length, certData.Length);

                // If we ran out of space in the destination, return false. It's okay
                // that we may have successfully written data to the destination
                // already. Since certificates only contain "public" information,
                // we don't need to clear what has been written already.
                if (buffer.Length < certSize)
                {
                    charsWritten = 0;
                    return(false);
                }

                if (!PemEncoding.TryWrite(PemLabels.X509Certificate, certData.Span, buffer, out int certWritten) ||
                    certWritten != certSize)
                {
                    Debug.Fail("Presized buffer is too small or did not write the correct amount.");
                    throw new CryptographicException();
                }

                buffer   = buffer.Slice(certWritten);
                written += certWritten;

                // write a new line if not the last certificate.
                if (i < Count - 1)
                {
                    if (buffer.IsEmpty)
                    {
                        charsWritten = 0;
                        return(false);
                    }

                    // Always use Unix line endings between certificates to match the
                    // behavior of PemEncoding.TryWrite, which is following RFC 7468.
                    buffer[0] = '\n';
                    buffer    = buffer.Slice(1);
                    written++;
                }
            }

            charsWritten = written;
            return(true);
        }
예제 #18
0
        internal static string CreatePemFromData(string label, ReadOnlyMemory <byte> data)
        {
            int pemSize = PemEncoding.GetEncodedSize(label.Length, data.Length);

            return(string.Create(pemSize, (label, data), static (destination, args) =>
            {
                (string label, ReadOnlyMemory <byte> data) = args;

                if (!PemEncoding.TryWrite(label, data.Span, destination, out int charsWritten) ||
                    charsWritten != destination.Length)
                {
                    Debug.Fail("Pre-allocated buffer was not the correct size.");
                    throw new CryptographicException();
                }
            }));
예제 #19
0
        private string ToPEMCertificateChain(byte[] orderCertificate)
        {
            var certificateCollection = new X509Certificate2Collection();

            certificateCollection.Import(orderCertificate);

            var stringBuilder = new StringBuilder();

            foreach (var certificate in certificateCollection)
            {
                var certPem = PemEncoding.Write("CERTIFICATE", certificate.Export(X509ContentType.Cert));
                stringBuilder.AppendLine(new string(certPem));
            }

            return(stringBuilder.ToString());
        }
예제 #20
0
        private int GetCertificatePemsSize()
        {
            checked
            {
                int size = 0;

                for (int i = 0; i < Count; i++)
                {
                    size += PemEncoding.GetEncodedSize(PemLabels.X509Certificate.Length, this[i].RawDataMemory.Length);

                    // Add a \n character between each certificate, except the last one.
                    if (i < Count - 1)
                    {
                        size += 1;
                    }
                }

                return(size);
            }
        }
        internal CertificateData(byte[] rawData)
        {
#if DEBUG
            try
            {
#endif
            RawData     = rawData;
            certificate = CertificateAsn.Decode(rawData, AsnEncodingRules.DER);
            certificate.TbsCertificate.ValidateVersion();
            Issuer      = new X500DistinguishedName(certificate.TbsCertificate.Issuer.Span);
            Subject     = new X500DistinguishedName(certificate.TbsCertificate.Subject.Span);
            IssuerName  = Issuer.Name;
            SubjectName = Subject.Name;

            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
            certificate.TbsCertificate.SubjectPublicKeyInfo.Encode(writer);
            SubjectPublicKeyInfo = writer.Encode();

            Extensions = new List <X509Extension>((certificate.TbsCertificate.Extensions?.Length).GetValueOrDefault());
            if (certificate.TbsCertificate.Extensions != null)
            {
                foreach (X509ExtensionAsn rawExtension in certificate.TbsCertificate.Extensions)
                {
                    X509Extension extension = new X509Extension(
                        rawExtension.ExtnId,
                        rawExtension.ExtnValue.Span,
                        rawExtension.Critical);

                    Extensions.Add(extension);
                }
            }
#if DEBUG
        }

        catch (Exception e)
        {
            string pem = PemEncoding.WriteString(PemLabels.X509Certificate, rawData);
            throw new CryptographicException($"Error in reading certificate:{Environment.NewLine}{pem}", e);
        }
#endif
        }
예제 #22
0
        private static byte[] SerializeCertificate(X509Certificate certificate)
        {
            if (certificate == null)
            {
                return(null);
            }

            char[] pemEncoded =
                PemEncoding.Write(
                    "CERTIFICATE",
                    certificate.Export(X509ContentType.Cert));

            // Append a \n character at the end
            var length = Encoding.UTF8.GetByteCount(pemEncoded) + 1;
            var bytes  = new byte[length];

            Encoding.UTF8.GetBytes(pemEncoded, bytes);
            bytes[length - 1] = 0xA;

            return(bytes);
        }
예제 #23
0
        private static byte[] SerializePrivateKey(RSA privateKey)
        {
            if (privateKey == null)
            {
                return(null);
            }

            var pemEncoded =
                PemEncoding.Write(
                    "RSA PRIVATE KEY",
                    privateKey.ExportRSAPrivateKey());

            // Append a \n character at the end
            var length = Encoding.UTF8.GetByteCount(pemEncoded) + 1;
            var bytes  = new byte[length];

            Encoding.UTF8.GetBytes(pemEncoded, bytes);
            bytes[length - 1] = 0xA;

            return(bytes);
        }
예제 #24
0
        private static void WriteCertificateBundle(FileInfo certificateBundle, X509Certificate2Collection certificates)
        {
            FileInfo file = new(Path.GetTempFileName());

            try
            {
                using (StreamWriter writer = new(file.FullName))
                {
                    foreach (X509Certificate2 certificate in certificates)
                    {
                        char[] pem = PemEncoding.Write("CERTIFICATE", certificate.RawData);

                        writer.WriteLine(pem);
                        writer.WriteLine();
                    }
                }

                File.Copy(file.FullName, certificateBundle.FullName, overwrite: true);
            }
            finally
            {
                file.Delete();
            }
        }
예제 #25
0
        public static unsafe bool TryExportToEncryptedPem <T>(
            T arg,
            ReadOnlySpan <char> password,
            PbeParameters pbeParameters,
            TryExportEncryptedKeyAction <T> exporter,
            Span <char> destination,
            out int charsWritten)
        {
            int bufferSize = 4096;

            while (true)
            {
                byte[] buffer       = CryptoPool.Rent(bufferSize);
                int    bytesWritten = 0;
                bufferSize = buffer.Length;

                // Fixed to prevent GC moves.
                fixed(byte *bufferPtr = buffer)
                {
                    try
                    {
                        if (exporter(arg, password, pbeParameters, buffer, out bytesWritten))
                        {
                            Span <byte> writtenSpan = new Span <byte>(buffer, 0, bytesWritten);
                            return(PemEncoding.TryWrite(PemLabels.EncryptedPkcs8PrivateKey, writtenSpan, destination, out charsWritten));
                        }
                    }
                    finally
                    {
                        CryptoPool.Return(buffer, bytesWritten);
                    }

                    bufferSize = checked (bufferSize * 2);
                }
            }
        }
예제 #26
0
        /// <summary>
        /// Converts this <see cref="X509Certificate2"/> to a <see cref="V1Secret"/>.
        /// </summary>
        /// <param name="certificate">
        /// A <see cref="X509Certificate2"/> which represents a TLS certificate.
        /// </param>
        /// <returns>
        /// The equivalent <see cref="V1Secret"/>.
        /// </returns>
        public static V1Secret AsSecret(this X509Certificate2 certificate)
        {
            var secret = new V1Secret()
            {
                ApiVersion = V1Secret.KubeApiVersion,
                Kind       = V1Secret.KubeKind,
                Type       = TlsType,
                Metadata   = new V1ObjectMeta()
                {
                    // Must conform to a DNS subdomain naming rules, so all lowercase ASCII.
                    Name   = certificate.Thumbprint.ToLowerInvariant(),
                    Labels = new Dictionary <string, string>(),
                },
                Data      = new Dictionary <string, byte[]>(),
                Immutable = true,
            };

            var certificateAsPem =
                PemEncoding.Write(
                    "CERTIFICATE",
                    certificate.Export(X509ContentType.Cert));

            secret.Data[TlsCertificate] = Encoding.UTF8.GetBytes(certificateAsPem);

            if (certificate.PrivateKey != null)
            {
                var keyAsPem =
                    PemEncoding.Write(
                        "PRIVATE KEY",
                        certificate.PrivateKey.ExportPkcs8PrivateKey());

                secret.Data[TlsPrivateKey] = Encoding.UTF8.GetBytes(keyAsPem);
            }

            return(secret);
        }
예제 #27
0
 protected override void AssertNoPemFound(ReadOnlySpan <char> input)
 {
     AssertExtensions.Throws <ArgumentException, char>("pemData", input, x => PemEncoding.Find(x));
 }
예제 #28
0
 protected override PemFields FindPem(ReadOnlySpan <char> input) => PemEncoding.Find(input);
예제 #29
0
        protected override void AssertNoPemFound(ReadOnlySpan <char> input)
        {
            bool found = PemEncoding.TryFind(input, out _);

            Assert.False(found, "Found PEM when not expected");
        }
예제 #30
0
        internal void ExportCertificate(X509Certificate2 certificate, string path, bool includePrivateKey, string password, CertificateKeyExportFormat format)
        {
            Log.ExportCertificateStart(GetDescription(certificate), path, includePrivateKey);
            if (includePrivateKey && password == null)
            {
                Log.NoPasswordForCertificate();
            }

            var targetDirectoryPath = Path.GetDirectoryName(path);

            if (targetDirectoryPath != "")
            {
                Log.CreateExportCertificateDirectory(targetDirectoryPath);
                Directory.CreateDirectory(targetDirectoryPath);
            }

            byte[] bytes;
            byte[] keyBytes;
            byte[] pemEnvelope = null;
            RSA    key         = null;

            try
            {
                if (includePrivateKey)
                {
                    switch (format)
                    {
                    case CertificateKeyExportFormat.Pfx:
                        bytes = certificate.Export(X509ContentType.Pkcs12, password);
                        break;

                    case CertificateKeyExportFormat.Pem:
                        key = certificate.GetRSAPrivateKey();

                        char[] pem;
                        if (password != null)
                        {
                            keyBytes    = key.ExportEncryptedPkcs8PrivateKey(password, new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 100000));
                            pem         = PemEncoding.Write("ENCRYPTED PRIVATE KEY", keyBytes);
                            pemEnvelope = Encoding.ASCII.GetBytes(pem);
                        }
                        else
                        {
                            // Export the key first to an encrypted PEM to avoid issues with System.Security.Cryptography.Cng indicating that the operation is not supported.
                            // This is likely by design to avoid exporting the key by mistake.
                            // To bypass it, we export the certificate to pem temporarily and then we import it and export it as unprotected PEM.
                            keyBytes = key.ExportEncryptedPkcs8PrivateKey("", new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 1));
                            pem      = PemEncoding.Write("ENCRYPTED PRIVATE KEY", keyBytes);
                            key.Dispose();
                            key = RSA.Create();
                            key.ImportFromEncryptedPem(pem, "");
                            Array.Clear(keyBytes, 0, keyBytes.Length);
                            Array.Clear(pem, 0, pem.Length);
                            keyBytes    = key.ExportPkcs8PrivateKey();
                            pem         = PemEncoding.Write("PRIVATE KEY", keyBytes);
                            pemEnvelope = Encoding.ASCII.GetBytes(pem);
                        }

                        Array.Clear(keyBytes, 0, keyBytes.Length);
                        Array.Clear(pem, 0, pem.Length);

                        bytes = certificate.Export(X509ContentType.Cert);
                        break;

                    default:
                        throw new InvalidOperationException("Unknown format.");
                    }
                }
                else
                {
                    bytes = certificate.Export(X509ContentType.Cert);
                }
            }
            catch (Exception e)
            {
                Log.ExportCertificateError(e.ToString());
                throw;
            }
            finally
            {
                key?.Dispose();
            }

            try
            {
                Log.WriteCertificateToDisk(path);
                File.WriteAllBytes(path, bytes);
            }
            catch (Exception ex)
            {
                Log.WriteCertificateToDiskError(ex.ToString());
                throw;
            }
            finally
            {
                Array.Clear(bytes, 0, bytes.Length);
            }

            if (includePrivateKey && format == CertificateKeyExportFormat.Pem)
            {
                try
                {
                    var keyPath = Path.ChangeExtension(path, ".key");
                    Log.WritePemKeyToDisk(keyPath);
                    File.WriteAllBytes(keyPath, pemEnvelope);
                }
                catch (Exception ex)
                {
                    Log.WritePemKeyToDiskError(ex.ToString());
                    throw;
                }
                finally
                {
                    Array.Clear(pemEnvelope, 0, pemEnvelope.Length);
                }
            }
        }