通常のTcpClient
ではなくSslStream
でTLSを使用するように私のアプリケーションのStream
を更新しようとしています。 2017年も同様にプロジェクト。
接続を確立して新しいSslStream
を開くには、次のコードを使用します。
public static void InitClient(string hostName, int port, string certificateName)
{
client = new TcpClient(hostName, port);
if (client.Client.Connected)
{
Debug.LogFormat("Client connected succesfully");
}
else
{
Debug.LogErrorFormat("Client couldn't connect");
return;
}
stream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
try
{
stream.AuthenticateAsClient(certificateName);
}
catch (AuthenticationException e)
{
Debug.LogErrorFormat("Error authenticating: {0}", e);
if (e.InnerException != null)
{
Debug.LogErrorFormat("Inner exception: {0}", e);
}
Debug.LogErrorFormat("Authentication failed - closing connection");
stream.Close();
client.Close();
}
}
証明書を検証するために
public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Debug.LogErrorFormat("Certificate error: {0}", sslPolicyErrors);
return false;
}
Unity 2019.1.8では、クライアントが接続し、エラーで失敗したリモート証明書を検証しようとします.TlsException: Handshake failed - error code: UNITYTLS_INTERNAL_ERROR, verify result: UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED.
ValidateServerCertificate
を常に返すtrue
は、私のクライアントが問題なく接続することができます。
まったく同じコードを使用して、.NET Framework 4.7.1を使用して、.NET Framework 4.7.1をターゲットにしたスタンドアロンC#コンソールアプリケーションの問題の複製を試みました。このアプリケーションでクライアントを起動すると、sslPolicyErrors == SslPolicyErrors.None
チェックからtrue
からValidateServerCertificate
が返されます。
私は、証明書が信頼できるCAによって発行された有効な証明書であることを知っています(Certがコンソールアプリから受け入れられ、ブラウザに南京錠を持っているという事実によって検証されている)。
検証が統一に失敗するのはなぜですか?
Unityがオプション1を検証できない理由:
[。]証明書は有効かつ正しい(例えば、Webブラウザで使用するときに機能します)、それはNot =中間証明書チェーンをルートCAに含めました。これは、信頼の連鎖を形成できないことがあります(Unityは中間体をキャッシュ/検索しない)、その結果、UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED
フラグが設定されています。
これを修正するには、Unityがチェーン全体をルートCAまで検証できるように、証明書チェーンを自分のリーフ証明書に追加する必要がありました。証明書の証明書チェーンを見つけるには、「TLS証明書チェーン作曲家」を使用できます。
あなたが使用するソフトウェアに応じて、あなたの証明書にチェーンを含める必要があるかもしれません、またはそれを分離されたファイルに保持することができます。から whatsmychaincert (私はこのサイトには関係なく、単に使いました):
注意:ソフトウェアでは、サイトの証明書(例:example.com.crtなど)とチェーン証明書(例:example.com.chain.crtなど)を別々のファイルに入れる必要がありますが、他のソフトウェアはサイトの後にチェーン証明書を配置する必要があります。同じファイル内の証明書。
Unityがオプション2を検証できない理由:
[。]サーバーのSSL証明書が期限切れになったとき、Unityは、証明書が満了している追加情報なしでまったく同じUNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED
エラーをスローしますので、「有効な」日付が将来的にあることを確認します(これはWebブラウザで使用すると、証明書を拒否されます。
ブラウザ/コンソールアプリCAN検証:
[。]ソフトウェアは、それが不完全なチェーンをどのように扱うかについて異なる実装を持つことができます。チェーンが壊れていることを確認し、(Unityの場合と同様)、または後でキャッシュを保存することはできません(ブラウザやMicrosoftの.NETとして)、信頼できないことを確認できます。 (コア)。
[。]で説明されているように この回答 (強調鉱山)
一般に、SSL/TLSクライアントはサーバーから受信したサーバー証明書チェーンを検証しようとします。そのチェーンがクライアントを喜ばない場合、クライアントの動作は実装によって異なります。一部のクライアントは単にあきらめます。 その他(特にWindows/Internet Explorer)は、ローカルで既知の中間CAを使用して別のチェーンを構築し、他の証明書にあるURLからの証明書をダウンロードしようとします( - === - )権限情報アクセス "拡張子).
この問題を使用して、OpenSSL/MBEDTLを使用してroot証明書に対して検証するのではなく、システム固有のTLS APIを介して検証を行うことができますが、このソリューションはクロスプラットフォームでは動作しません。そのため、すべてのプラットフォームではなく、ユーザーからMISCONFIGEDUREEDサーバーを非表示にするため、今日実装したくはありません。
この質問をする間、これは私の特定状況の解決策であったので、将来の参照のためにそれを自己回答することを決めました。しかし、UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED
すべての種類の原因を持つことができます、これはただそれらの一つです。
UnityWebRequest
とを使用している人にわたってうまくつまずく人のために encrypt :
nityの問題トラッカーで既知の問題があります それが特定のバージョンのみで修正されているのを見つけることができます。
既存のプロジェクトのUnityバージョンの変更は簡単なタスクではありません。これは、安価ではないが、最も単純な解決策でした。
私の解決策は次のとおりです。
> Public class ForceAcceptAll : CertificateHandler {
> protected override bool ValidateCertificate(byte[] certificateData)
> {
> return true;
> } }
_
//------
var cert = new ForceAcceptAll();
// www is a UnityWebRequest
www.certificateHandler = cert;
_
Nota:誤って使用されていれば(Googleによって見つけられ、あなたのビルドは拒否されるかもしれません)。
だから注意してそれを使用してください。
詳細情報 こちら 。