File: System\Security\Cryptography\X509Certificates\CertificateExtensionsCommon.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;
 
namespace System.Security.Cryptography.X509Certificates
{
    internal static class CertificateExtensionsCommon
    {
        public static T? GetPublicKey<T>(
            this X509Certificate2 certificate,
            Predicate<X509Certificate2>? matchesConstraints = null)
            where T : AsymmetricAlgorithm
        {
            ArgumentNullException.ThrowIfNull(certificate);
 
            string oidValue = GetExpectedOidValue<T>();
            PublicKey publicKey = certificate.PublicKey;
            Oid algorithmOid = publicKey.Oid;
 
            if (oidValue != algorithmOid.Value)
                return null;
 
            if (matchesConstraints != null && !matchesConstraints(certificate))
                return null;
 
            if (typeof(T) == typeof(RSA) || typeof(T) == typeof(DSA))
            {
                byte[] rawEncodedKeyValue = publicKey.EncodedKeyValue.RawData;
                byte[] rawEncodedParameters = publicKey.EncodedParameters.RawData;
                return (T)(X509Pal.Instance.DecodePublicKey(algorithmOid, rawEncodedKeyValue, rawEncodedParameters, certificate.Pal));
            }
            else if (typeof(T) == typeof(ECDsa))
            {
                return (T)(object)(X509Pal.Instance.DecodeECDsaPublicKey(certificate.Pal));
            }
            else if (typeof(T) == typeof(ECDiffieHellman))
            {
                return (T)(object)(X509Pal.Instance.DecodeECDiffieHellmanPublicKey(certificate.Pal));
            }
 
            Debug.Fail("Expected GetExpectedOidValue() to have thrown before we got here.");
            throw new NotSupportedException(SR.NotSupported_KeyAlgorithm);
        }
 
        public static T? GetPrivateKey<T>(
            this X509Certificate2 certificate,
            Predicate<X509Certificate2>? matchesConstraints = null)
            where T : AsymmetricAlgorithm
        {
            ArgumentNullException.ThrowIfNull(certificate);
 
            string oidValue = GetExpectedOidValue<T>();
            if (!certificate.HasPrivateKey || oidValue != certificate.PublicKey.Oid.Value)
                return null;
 
            if (matchesConstraints != null && !matchesConstraints(certificate))
                return null;
 
            if (typeof(T) == typeof(RSA))
                return (T?)(object?)certificate.Pal.GetRSAPrivateKey();
 
            if (typeof(T) == typeof(ECDsa))
                return (T?)(object?)certificate.Pal.GetECDsaPrivateKey();
 
            if (typeof(T) == typeof(DSA))
                return (T?)(object?)certificate.Pal.GetDSAPrivateKey();
 
            if (typeof(T) == typeof(ECDiffieHellman))
                return (T?)(object?)certificate.Pal.GetECDiffieHellmanPrivateKey();
 
            Debug.Fail("Expected GetExpectedOidValue() to have thrown before we got here.");
            throw new NotSupportedException(SR.NotSupported_KeyAlgorithm);
        }
 
        private static string GetExpectedOidValue<T>() where T : AsymmetricAlgorithm
        {
            if (typeof(T) == typeof(RSA))
                return Oids.Rsa;
            if (typeof(T) == typeof(ECDsa) || typeof(T) == typeof(ECDiffieHellman))
                // Neither Windows nor OpenSSL permit id-ECDH as the SPKI public key algorithm.
                return Oids.EcPublicKey;
            if (typeof(T) == typeof(DSA))
                return Oids.Dsa;
            throw new NotSupportedException(SR.NotSupported_KeyAlgorithm);
        }
    }
}