File: System\Security\Cryptography\X509Certificates\OpenSslExportProvider.cs
Web Access
Project: src\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using Microsoft.Win32.SafeHandles;
 
namespace System.Security.Cryptography.X509Certificates
{
    internal sealed class OpenSslExportProvider : UnixExportProvider
    {
        internal OpenSslExportProvider(ICertificatePalCore singleCertPal)
            : base(singleCertPal)
        {
        }
 
        internal OpenSslExportProvider(X509Certificate2Collection certs)
            : base(certs)
        {
        }
 
        protected override byte[] ExportPkcs8(
            ICertificatePalCore certificatePal,
            ReadOnlySpan<char> password)
        {
            SafeEvpPKeyHandle? privateKey = ((OpenSslX509CertificateReader)certificatePal).PrivateKeyHandle;
 
            if (privateKey == null)
            {
                throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
            }
 
            Interop.Crypto.EvpAlgorithmId evpAlgId = Interop.Crypto.EvpPKeyType(privateKey);
 
            AsymmetricAlgorithm alg = evpAlgId switch
            {
                Interop.Crypto.EvpAlgorithmId.RSA => new RSAOpenSsl(privateKey),
                Interop.Crypto.EvpAlgorithmId.ECC => new ECDsaOpenSsl(privateKey),
                Interop.Crypto.EvpAlgorithmId.DSA => new DSAOpenSsl(privateKey),
                _ => throw new CryptographicException(SR.Cryptography_InvalidHandle),
            };
 
            return alg.ExportEncryptedPkcs8PrivateKey(password, s_windowsPbe);
        }
 
        private static void PushHandle(IntPtr certPtr, SafeX509StackHandle publicCerts)
        {
            using (SafeX509Handle certHandle = Interop.Crypto.X509UpRef(certPtr))
            {
                if (!Interop.Crypto.PushX509StackField(publicCerts, certHandle))
                {
                    throw Interop.Crypto.CreateOpenSslCryptographicException();
                }
 
                // The handle ownership has been transferred into the STACK_OF(X509).
                certHandle.SetHandleAsInvalid();
            }
        }
 
        protected override byte[] ExportPkcs7()
        {
            // Pack all of the certificates into a new PKCS7*, export it to a byte[],
            // then free the PKCS7*, since we don't need it any more.
            using (SafeX509StackHandle certs = Interop.Crypto.NewX509Stack())
            {
                foreach (X509Certificate2 cert in _certs!)
                {
                    PushHandle(cert.Handle, certs);
                    GC.KeepAlive(cert); // ensure cert's safe handle isn't finalized while raw handle is in use
                }
 
                using (SafePkcs7Handle pkcs7 = Interop.Crypto.Pkcs7CreateCertificateCollection(certs))
                {
                    Interop.Crypto.CheckValidOpenSslHandle(pkcs7);
                    return Interop.Crypto.OpenSslEncode(
                        Interop.Crypto.GetPkcs7DerSize,
                        Interop.Crypto.EncodePkcs7,
                        pkcs7);
                }
            }
        }
    }
}