.net core DotNet Core:如何跨平台客户端证书TLS身份验证?

.net core DotNet Core:如何跨平台客户端证书TLS身份验证?,.net-core,smartcard,pkcs#11,hsm,pkcs11interop,.net Core,Smartcard,Pkcs#11,Hsm,Pkcs11interop,我正在尝试开发一个跨平台的应用程序(windows/mac os x),它需要使用ClientCertificate身份验证在服务器上对XML文件进行签名并发出web请求 主要限制是我需要在智能卡上使用证书 目前我正在使用DotnetCore2.1 首先,我尝试使用dotnet core X509Store,但在MacOs上,我无论如何都无法访问PrivateKey对象(对于XML签名是必需的),然后我放弃了这一线索 然后,我将pkcs11interop与特定于供应商的DLL一起使用来访问智能卡

我正在尝试开发一个跨平台的应用程序(windows/mac os x),它需要使用ClientCertificate身份验证在服务器上对XML文件进行签名并发出web请求

主要限制是我需要在智能卡上使用证书

目前我正在使用DotnetCore2.1

首先,我尝试使用dotnet core X509Store,但在MacOs上,我无论如何都无法访问PrivateKey对象(对于XML签名是必需的),然后我放弃了这一线索

然后,我将pkcs11interop与特定于供应商的DLL一起使用来访问智能卡,它对XML签名很有效(我将pkcs11interop调用包装在RSA对象中,然后将此对象用作SignedXml中的SigningKey),但它对ClientCertificate连接不起作用

通常我使用此方法连接到服务器(dotnet framework 4.6.1,仅限windows):

并生成证书:

var certAttr = session.GetAttributeValue(handle, new List<CKA>
{
    CKA.CKA_VALUE,
};
var cert = new X509Certificate2(certAttr[0].GetValueAsByteArray());
我想知道不使用第三方库是否可以做到这一点

注意:法语错误消息“消息意外或格式不正确”的翻译

谢谢


(编辑:更好的格式)

X509Certificate2
是仅为当前没有广泛可用替代品或sane多平台替代品的Windows设计的传统类

当您使用
CKA\u value
属性的
byte[]
值构造
X509Certificate2
对象时,您只会得到不带私钥的证书

最接近“.NET兼容实现”的方法是实现从
RSA
派生的类,就像我在project中所做的那样。它可以用于
SignedXML
类,但正如您已经发现的那样,它不能用于大多数需要
X509Certificate2
对象并具有正确关联的
PrivateKey
属性的SSL类

在我看来,你有三个选择:

  • 切换到适当的.NET核心版本,并使用@FilipNavara在其评论中指出的方法创建与
    RSA
    实现关联的
    X509Certificate2
    对象。这样的
    X509Certificate2
    对象可能(或者更确切地说可能不)与SSL实现一起工作

  • 使用PFX/PKCS#12文件,该文件包含SSL客户端证书,私钥受用户密码保护。在.NET Core支持的大多数平台上,此类文件可以加载到正确关联的
    X509Certificate2
    对象
    PrivateKey
    属性中

  • 查找或编写不需要
    X509Certificate2
    对象和关联的
    PrivateKey
    属性的SSL客户端实现。我目前还不知道有哪家图书馆有这样的设计


  • PrivateKey
    属性设置器已替换为支持RSA、DSA和ECC(例如)的
    CopyWithPrivateKey
    扩展方法。所有这些都在所有平台的.NETCore上工作。@FilipNavara thx指出了这个方法!如果SSL实现将使用
    RSA
    ,这可能会改变游戏规则。谢谢,我错过了这个方法,我会尽快尝试。遗憾的是,它不起作用。CopyWithPrivateKey需要私钥的指数和模数,无法从智能卡中提取私钥指数。。。我正在调查bouncycastle,看起来很有希望?
    var certAttr = session.GetAttributeValue(handle, new List<CKA>
    {
        CKA.CKA_VALUE,
    };
    var cert = new X509Certificate2(certAttr[0].GetValueAsByteArray());
    
    System.Net.WebException: The SSL connection could not be established, see inner exception. Authentication failed, see inner exception.
    ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
    ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
    ---> System.ComponentModel.Win32Exception: Le message reçu était inattendu ou formaté de façon incorrecte
       --- End of inner exception stack trace ---
       at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
       at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
       at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
       at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
       at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
       at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Net.Security.SslState.ThrowIfExceptional()
       at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
       at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
       at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
       at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__47_1(IAsyncResult iar)
       at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
       --- End of inner exception stack trace ---
       at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
       at System.Threading.Tasks.ValueTask`1.get_Result()
       at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
       at System.Threading.Tasks.ValueTask`1.get_Result()
       at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)
       at System.Threading.Tasks.ValueTask`1.get_Result()
       at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
       at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
       at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
       at System.Net.HttpWebRequest.SendRequest()
       at System.Net.HttpWebRequest.GetResponse()
       --- End of inner exception stack trace ---
       at System.Net.HttpWebRequest.GetResponse()
    ...
    
    cert.PrivateKey = myRSAObject; // simple