public void Remove(ICertificatePal certPal)
        {
            if (!Directory.Exists(_storePath))
            {
                return;
            }

            OpenSslX509CertificateReader cert = (OpenSslX509CertificateReader)certPal;

            using (X509Certificate2 copy = new X509Certificate2(cert.DuplicateHandles()))
            {
                string?currentFilename;

                do
                {
                    bool hadCandidates;
                    currentFilename = FindExistingFilename(copy, _storePath, out hadCandidates);

                    if (currentFilename != null)
                    {
                        if (_readOnly)
                        {
                            // Windows compatibility, the readonly check isn't done until after a match is found.
                            throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly);
                        }

                        File.Delete(currentFilename);
                        ChainPal.FlushStores();
                    }
                } while (currentFilename != null);
            }
        }
        public static ICertificatePal FromOtherCert(X509Certificate cert)
        {
            Debug.Assert(cert.Pal != null);

            // Ensure private key is copied
            OpenSslX509CertificateReader certPal = (OpenSslX509CertificateReader)cert.Pal;

            return(certPal.DuplicateHandles());
        }
        private void AddCertToStore(ICertificatePal certPal)
        {
            // This may well be the first time that we've added something to this store.
            Directory.CreateDirectory(_storePath);

            uint userId = Interop.Sys.GetEUid();

            EnsureDirectoryPermissions(_storePath, userId);

            OpenSslX509CertificateReader cert = (OpenSslX509CertificateReader)certPal;

            using (X509Certificate2 copy = new X509Certificate2(cert.DuplicateHandles()))
            {
                string thumbprint = copy.Thumbprint;
                bool   findOpenSlot;

                // The odds are low that we'd have a thumbprint collision, but check anyways.
                string?existingFilename = FindExistingFilename(copy, _storePath, out findOpenSlot);

                if (existingFilename != null)
                {
                    if (!copy.HasPrivateKey)
                    {
                        return;
                    }

                    try
                    {
                        using (X509Certificate2 fromFile = new X509Certificate2(existingFilename))
                        {
                            if (fromFile.HasPrivateKey)
                            {
                                // We have a private key, the file has a private key, we're done here.
                                return;
                            }
                        }
                    }
                    catch (CryptographicException)
                    {
                        // We can't read this file anymore, but a moment ago it was this certificate,
                        // so go ahead and overwrite it.
                    }
                }

                const UnixFileMode UserReadWrite = UnixFileMode.UserRead | UnixFileMode.UserWrite;

                string            destinationFilename;
                FileStreamOptions options = new()
                {
                    Mode           = FileMode.CreateNew,
                    UnixCreateMode = UserReadWrite,
                    Access         = FileAccess.Write
                };

                if (existingFilename != null)
                {
                    destinationFilename = existingFilename;
                    options.Mode        = FileMode.Create;

                    // Before we open the file for writing the certificate,
                    // ensure it is only accessible to the owner.
                    try
                    {
                        File.SetUnixFileMode(existingFilename, UserReadWrite);
                    }
                    catch (IOException) // Ignore errors. We verify permissions when we've opened the file.
                    { }
                }
                else if (findOpenSlot)
                {
                    destinationFilename = FindOpenSlot(thumbprint);
                }
                else
                {
                    destinationFilename = Path.Combine(_storePath, thumbprint + PfxExtension);
                }

                using (FileStream stream = new FileStream(destinationFilename, options))
                {
                    // Verify the file can only be read/written to by the owner.
                    UnixFileMode actualMode = File.GetUnixFileMode(stream.SafeFileHandle);
                    if (actualMode != UserReadWrite)
                    {
                        throw new CryptographicException(SR.Format(SR.Cryptography_InvalidFilePermissions, stream.Name));
                    }

                    byte[] pkcs12 = copy.Export(X509ContentType.Pkcs12) !;
                    stream.Write(pkcs12, 0, pkcs12.Length);
                }
            }
        }
        private void AddCertToStore(ICertificatePal certPal)
        {
            // This may well be the first time that we've added something to this store.
            Directory.CreateDirectory(_storePath);

            uint userId = Interop.Sys.GetEUid();

            EnsureDirectoryPermissions(_storePath, userId);

            OpenSslX509CertificateReader cert = (OpenSslX509CertificateReader)certPal;

            using (X509Certificate2 copy = new X509Certificate2(cert.DuplicateHandles()))
            {
                string thumbprint = copy.Thumbprint;
                bool   findOpenSlot;

                // The odds are low that we'd have a thumbprint collision, but check anyways.
                string?existingFilename = FindExistingFilename(copy, _storePath, out findOpenSlot);

                if (existingFilename != null)
                {
                    if (!copy.HasPrivateKey)
                    {
                        return;
                    }

                    try
                    {
                        using (X509Certificate2 fromFile = new X509Certificate2(existingFilename))
                        {
                            if (fromFile.HasPrivateKey)
                            {
                                // We have a private key, the file has a private key, we're done here.
                                return;
                            }
                        }
                    }
                    catch (CryptographicException)
                    {
                        // We can't read this file anymore, but a moment ago it was this certificate,
                        // so go ahead and overwrite it.
                    }
                }

                string   destinationFilename;
                FileMode mode = FileMode.CreateNew;

                if (existingFilename != null)
                {
                    destinationFilename = existingFilename;
                    mode = FileMode.Create;
                }
                else if (findOpenSlot)
                {
                    destinationFilename = FindOpenSlot(thumbprint);
                }
                else
                {
                    destinationFilename = Path.Combine(_storePath, thumbprint + PfxExtension);
                }

                using (FileStream stream = new FileStream(destinationFilename, mode))
                {
                    EnsureFilePermissions(stream, userId);
                    byte[] pkcs12 = copy.Export(X509ContentType.Pkcs12) !;
                    stream.Write(pkcs12, 0, pkcs12.Length);
                }
            }
        }