File: System\Security\Cryptography\X509Certificates\OpenSslPkcs12Reader.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.CodeAnalysis;
using System.Formats.Asn1;
using System.Security.Cryptography.Asn1;
 
namespace System.Security.Cryptography.X509Certificates
{
    internal sealed class OpenSslPkcs12Reader : UnixPkcs12Reader
    {
        private OpenSslPkcs12Reader()
        {
        }
 
        protected override ICertificatePalCore ReadX509Der(ReadOnlyMemory<byte> data)
        {
            if (OpenSslX509CertificateReader.TryReadX509Der(data.Span, out ICertificatePal? ret))
            {
                return ret;
            }
 
            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
        }
 
        public static bool TryRead(ReadOnlySpan<byte> data, [NotNullWhen(true)] out OpenSslPkcs12Reader? pkcs12Reader) =>
            TryRead(data, out pkcs12Reader, out _, captureException: false);
 
        public static bool TryRead(ReadOnlySpan<byte> data, [NotNullWhen(true)] out OpenSslPkcs12Reader? pkcs12Reader, [NotNullWhen(false)] out Exception? openSslException) =>
            TryRead(data, out pkcs12Reader, out openSslException!, captureException: true);
 
        protected override AsymmetricAlgorithm LoadKey(ReadOnlyMemory<byte> pkcs8)
        {
            PrivateKeyInfoAsn privateKeyInfo = PrivateKeyInfoAsn.Decode(pkcs8, AsnEncodingRules.BER);
            AsymmetricAlgorithm key;
 
            switch (privateKeyInfo.PrivateKeyAlgorithm.Algorithm)
            {
                case Oids.Rsa:
                    key = new RSAOpenSsl();
                    break;
                case Oids.Dsa:
                    key = new DSAOpenSsl();
                    break;
                case Oids.EcDiffieHellman:
                case Oids.EcPublicKey:
                    key = new ECDiffieHellmanOpenSsl();
                    break;
                default:
                    throw new CryptographicException(
                        SR.Cryptography_UnknownAlgorithmIdentifier,
                        privateKeyInfo.PrivateKeyAlgorithm.Algorithm);
            }
 
            key.ImportPkcs8PrivateKey(pkcs8.Span, out int bytesRead);
 
            if (bytesRead != pkcs8.Length)
            {
                key.Dispose();
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }
 
            return key;
        }
 
        internal static SafeEvpPKeyHandle GetPrivateKey(AsymmetricAlgorithm key)
        {
            if (key is RSAOpenSsl rsa)
            {
                return rsa.DuplicateKeyHandle();
            }
 
            if (key is DSAOpenSsl dsa)
            {
                return dsa.DuplicateKeyHandle();
            }
 
            return ((ECDiffieHellmanOpenSsl)key).DuplicateKeyHandle();
        }
 
        private static bool TryRead(
            ReadOnlySpan<byte> data,
            [NotNullWhen(true)] out OpenSslPkcs12Reader? pkcs12Reader,
            out Exception? openSslException,
            bool captureException)
        {
            openSslException = null;
 
            try
            {
                pkcs12Reader = new OpenSslPkcs12Reader();
                pkcs12Reader.ParsePkcs12(data);
                return true;
            }
            catch (CryptographicException e)
            {
                if (captureException)
                {
                    openSslException = e;
                }
 
                pkcs12Reader = null;
                return false;
            }
        }
    }
}