using GostCryptography;
using GostCryptography.Asn1.Gost.Gost_R3410_2001;
using GostCryptography.Asn1.Gost.Gost_R3410_2012_256;
using GostCryptography.Asn1.Gost.Gost_R3410_2012_512;
using GostCryptography.Asn1.Gost.Gost_R3410_94;
using GostCryptography.Gost_R3410;
using GostCryptography.Native;
using System.Reflection;
// ReSharper disable once CheckNamespace
namespace System.Security.Cryptography.X509Certificates
{
///
/// Методы расширения
///
[SecurityCritical]
public static class X509CertificateHelper
{
///
/// Возвращает для сертификатов ГОСТ
///
public static bool IsGost(this X509Certificate2 certificate)
{
return certificate.IsGost_R3410_2012_512()
|| certificate.IsGost_R3410_2012_256()
|| certificate.IsGost_R3410_2001()
|| certificate.IsGost_R3410_94();
}
///
/// Возвращает для сертификатов ГОСТ Р 34.10-94
///
public static bool IsGost_R3410_94(this X509Certificate2 certificate)
{
return Gost_R3410_94_Constants.KeyAlgorithm.Value.Equals(certificate.GetKeyAlgorithm());
}
///
/// Возвращает для сертификатов ГОСТ Р 34.10-2001
///
public static bool IsGost_R3410_2001(this X509Certificate2 certificate)
{
return Gost_R3410_2001_Constants.KeyAlgorithm.Value.Equals(certificate.GetKeyAlgorithm());
}
///
/// Возвращает для сертификатов ГОСТ Р 34.10-2012/256
///
public static bool IsGost_R3410_2012_256(this X509Certificate2 certificate)
{
return Gost_R3410_2012_256_Constants.KeyAlgorithm.Value.Equals(certificate.GetKeyAlgorithm());
}
///
/// Возвращает для сертификатов ГОСТ Р 34.10-2012/512
///
public static bool IsGost_R3410_2012_512(this X509Certificate2 certificate)
{
return Gost_R3410_2012_512_Constants.KeyAlgorithm.Value.Equals(certificate.GetKeyAlgorithm());
}
///
/// Возвращает функции хэширования сертификата
///
///
///
public static Oid GetHashAlgorithm(this X509Certificate2 certificate)
{
if (certificate.IsGost_R3410_2012_512())
{
return Gost_R3410_2012_512_Constants.HashAlgorithm.ToOid();
}
if (certificate.IsGost_R3410_2012_256())
{
return Gost_R3410_2012_256_Constants.HashAlgorithm.ToOid();
}
if (certificate.IsGost_R3410_2001())
{
return Gost_R3410_2001_Constants.HashAlgorithm.ToOid();
}
if (certificate.IsGost_R3410_94())
{
return Gost_R3410_94_Constants.HashAlgorithm.ToOid();
}
return null;
}
private static volatile MethodInfo _getPrivateKeyInfoMethod;
private static readonly object GetPrivateKeyInfoMethodSync = new object();
///
/// Возвращает параметры закрытого ключа сертификата
///
///
///
public static CspParameters GetPrivateKeyInfo(this X509Certificate2 certificate)
{
if (certificate == null)
{
throw ExceptionUtility.ArgumentNull(nameof(certificate));
}
if (certificate.HasPrivateKey)
{
if (_getPrivateKeyInfoMethod == null)
{
lock (GetPrivateKeyInfoMethodSync)
{
if (_getPrivateKeyInfoMethod == null)
{
_getPrivateKeyInfoMethod = typeof(X509Certificate2).GetMethod("GetPrivateKeyInfo", BindingFlags.Static | BindingFlags.NonPublic);
}
}
}
if (_getPrivateKeyInfoMethod != null)
{
var certContext = GetCertContext(certificate);
if (certContext != null)
{
try
{
var parameters = new CspParameters();
var success = _getPrivateKeyInfoMethod.Invoke(null, new[] { certContext, parameters });
if (Equals(success, true))
{
return parameters;
}
}
catch
{
}
}
}
}
return null;
}
private static volatile MethodInfo _setPrivateKeyPropertyMethod;
private static readonly object SetPrivateKeyPropertyMethodSync = new object();
private static void SetPrivateKeyProperty(X509Certificate2 certificate, ICspAsymmetricAlgorithm privateKey)
{
if (_setPrivateKeyPropertyMethod == null)
{
lock (SetPrivateKeyPropertyMethodSync)
{
if (_setPrivateKeyPropertyMethod == null)
{
_setPrivateKeyPropertyMethod = typeof(X509Certificate2).GetMethod("SetPrivateKeyProperty", BindingFlags.Static | BindingFlags.NonPublic);
}
}
}
if (_setPrivateKeyPropertyMethod != null)
{
var certContext = GetCertContext(certificate);
if (certContext != null)
{
try
{
_setPrivateKeyPropertyMethod.Invoke(null, new[] { certContext, privateKey });
}
catch
{
}
}
}
}
private static volatile FieldInfo _certContextField;
private static readonly object CertContextFieldSync = new object();
private static object GetCertContext(X509Certificate2 certificate)
{
if (_certContextField == null)
{
lock (CertContextFieldSync)
{
if (_certContextField == null)
{
_certContextField = typeof(X509Certificate2).GetField("m_safeCertContext", BindingFlags.Instance | BindingFlags.NonPublic);
}
}
}
if (_certContextField != null)
{
try
{
return _certContextField.GetValue(certificate);
}
catch
{
}
}
return null;
}
///
/// Возвращает закрытый ключ сертификата
///
public static AsymmetricAlgorithm GetPrivateKeyAlgorithm(this X509Certificate2 certificate)
{
if (certificate.IsGost_R3410_2012_512())
{
var cspParameters = GetPrivateKeyInfo(certificate);
return new Gost_R3410_2012_512_AsymmetricAlgorithm(cspParameters);
}
if (certificate.IsGost_R3410_2012_256())
{
var cspParameters = GetPrivateKeyInfo(certificate);
return new Gost_R3410_2012_256_AsymmetricAlgorithm(cspParameters);
}
if (certificate.IsGost_R3410_2001())
{
var cspParameters = GetPrivateKeyInfo(certificate);
return new Gost_R3410_2001_AsymmetricAlgorithm(cspParameters);
}
return certificate.PrivateKey;
}
///
/// Возвращает открытый ключ сертификата
///
public static AsymmetricAlgorithm GetPublicKeyAlgorithm(this X509Certificate2 certificate)
{
if (certificate.IsGost_R3410_2012_512())
{
var publicKey = new Gost_R3410_2012_512_AsymmetricAlgorithm();
var encodedParameters = certificate.PublicKey.EncodedParameters.RawData;
var encodedKeyValue = certificate.PublicKey.EncodedKeyValue.RawData;
publicKey.ImportCspBlob(encodedParameters, encodedKeyValue);
return publicKey;
}
if (certificate.IsGost_R3410_2012_256())
{
var publicKey = new Gost_R3410_2012_256_AsymmetricAlgorithm();
var encodedParameters = certificate.PublicKey.EncodedParameters.RawData;
var encodedKeyValue = certificate.PublicKey.EncodedKeyValue.RawData;
publicKey.ImportCspBlob(encodedParameters, encodedKeyValue);
return publicKey;
}
if (certificate.IsGost_R3410_2001())
{
var publicKey = new Gost_R3410_2001_AsymmetricAlgorithm();
var encodedParameters = certificate.PublicKey.EncodedParameters.RawData;
var encodedKeyValue = certificate.PublicKey.EncodedKeyValue.RawData;
publicKey.ImportCspBlob(encodedParameters, encodedKeyValue);
return publicKey;
}
return certificate.PublicKey.Key;
}
///
/// Возвращает сертификат для указанного ключа
///
/// Ключ сертификата
/// Использовать ключ, как приватный
public static X509Certificate2 GetCertificate(this AsymmetricAlgorithm key, bool useAsPrivateKey = false)
{
X509Certificate2 certificate = null;
if (key is ISafeHandleProvider keyHandleProvider)
{
certificate = CryptoApiHelper.GetKeyCertificate(keyHandleProvider.SafeHandle);
}
if (useAsPrivateKey && (certificate != null) && (key is ICspAsymmetricAlgorithm privateKey))
{
SetPrivateKeyProperty(certificate, privateKey);
}
return certificate;
}
}
}