首页 > 解决方案 > 如何获取具有 oid 的 X509Certificate2 的 PrivateKey 不同于 1.2.840 ....?

问题描述

我已经使用提示命令创建了自签名证书

csptest -keyset -newkeyset -makecert -container test3 -keytype exchange

然后我使用 3rd-party 应用程序安装了它。当我试图PrivateKey在 asp.net 核心应用程序中获取证书时,它会抛出NotSupportedException.

var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
certificates = store1.Certificates;
var certificate = GetCertificateByThumbprint(certificates, "51F9748FE7DDE895DD100AAD0BE54C1ACF6B4DCC");

if (certificate.HasPrivateKey)
{
    var kayAlgorithm = = _certificate.GetKeyAlgorithm(); // same as certificate.PublicKey.Oid.Value;
    var rsaPrivateKey = certificate.GetRSAPrivateKey();
    var dsaPrivateKey = _certificate.GetDSAPrivateKey();
    var ecdsaPrivateKey = _certificate.GetECDsaPrivateKey();
    var privateKey = certificate.PrivateKey;
}

HasPrivateKey返回真。GetRSAPrivateKeyGetDSAPrivateKeyGetECDsaPrivateKey返回空值。但是GetKeyAlgorithm(oid.value)返回“1.2.643.7.1.1.1.1”。我更深入地研究了System.Security.Cryptography.X509Certificates.X509Certificate2库,发现那里只有“1.2.840.113549.1.1.1”或“1.2.840.10040.4.1”算法的硬编码检查。

public AsymmetricAlgorithm PrivateKey
{
  get
  {
    this.ThrowIfInvalid();
    if (!this.HasPrivateKey)
      return (AsymmetricAlgorithm) null;
    if (this._lazyPrivateKey == null)
    {
      string keyAlgorithm = this.GetKeyAlgorithm();
      if (!(keyAlgorithm == "1.2.840.113549.1.1.1"))
      {
        if (!(keyAlgorithm == "1.2.840.10040.4.1"))
          throw new NotSupportedException(SR.NotSupported_KeyAlgorithm);
        this._lazyPrivateKey = (AsymmetricAlgorithm) this.Pal.GetDSAPrivateKey();
      }
      else
        this._lazyPrivateKey = (AsymmetricAlgorithm) this.Pal.GetRSAPrivateKey();
    }
    return this._lazyPrivateKey;
  }
  set
  {
    throw new PlatformNotSupportedException();
  }
}

在 .net 框架中获取PrivateKey抛出相同的异常。System.Security.Cryptography.X509Certificates.X509Certificate2看起来不一样。

public AsymmetricAlgorithm PrivateKey
{
  get
  {
    if (!this.HasPrivateKey)
      return (AsymmetricAlgorithm) null;
    if (this.m_privateKey == null)
    {
      CspParameters parameters = new CspParameters();
      if (!X509Certificate2.GetPrivateKeyInfo(this.m_safeCertContext, ref parameters))
        return (AsymmetricAlgorithm) null;
      parameters.Flags |= CspProviderFlags.UseExistingKey;
      switch (this.PublicKey.AlgorithmId)
      {
        case 8704:
          this.m_privateKey = (AsymmetricAlgorithm) new DSACryptoServiceProvider(parameters);
          break;
        case 9216:
        case 41984:
          this.m_privateKey = (AsymmetricAlgorithm) new RSACryptoServiceProvider(parameters);
          break;
        default:
          throw new NotSupportedException(SR.GetString("NotSupported_KeyAlgorithm"));
      }
    }
    return this.m_privateKey;
  }
  set
  {
    ...
  }
}

那么,我怎样才能获得PrivateKey不同的算法,或者我之前做错了什么?

GetCertificateByThumbprint方法源代码以防万一。(我无法使用X509Certificate2Collection.Find方法,因为它不返回我的证书,因为它无效)

private X509Certificate2 GetCertificateByThumbprint(X509Certificate2Collection certifcates, string thumbprint)
    {
        foreach (var certificate in certifcates)
        {
            if (certificate.Thumbprint == thumbprint)
                return certificate;
        }
    }

标签: c#asp.net-corex509certificatex509certificate2

解决方案


由于 .NET 没有 GOST 的表示形式,因此 PrivateKey 属性实际上没有任何有用的东西可以返回(如果它还没有被有效地弃用)。

从 X509Certificate2 对象,您可以读取Handle属性以获取底层操作系统值(Windows 上的 PCERT_CONTEXT)。然后,您可以使用它来 P/Invoke 到操作系统函数中,例如CryptAcquireCertificatePrivateKey。假设 GOST CSP 在 Windows 中注册,该函数应该成功返回 CAPI 或 CNG 密钥句柄(由 dwKeySpec 返回确定),然后您需要继续使用 P/Invokes(可能通过 GOST 类你来管理它)。


推荐阅读