18

通信にTCP/IPソケットを使用しているさまざまなプロセス間で安全な通信を提供する必要があります。認証と暗号化の両方が必要です。車輪の再発明ではなく、SSLとSslStreamクラスおよび自己署名証明書を使用したいと思います。私がやりたいのは、ローカルアプリケーションの既知のコピーに対してリモートプロセスの証明書を検証することです。(証明書を手動でコピーするつもりなので、認証局は必要ありません)。

これを行うには、アプリケーションが最初に実行されたときに新しい証明書を自動的に生成できるようにする必要があります。makecert.exeに加えて、このリンクは自己署名証明書を自動的に生成する方法を示しているように見えるので、それが始まりです。

SslStreamのAuthenticateAsServerメソッドとAuthenticateAsClientメソッドを見てきました。確認のためにコールバックを提供できるため、可能であるように見えます。しかし、今はその詳細に精通しているので、これを行うことは本当に不可能だと思います。

私は正しい方向に進んでいますか?より良い代替案はありますか?誰かが以前にこのようなことをしたことがありますか(基本的にクライアントサーバーではなくピアツーピアSSL)?

4

3 に答える 3

29

ステップ1:自己署名証明書を生成する:

  • DougCookによって投稿されたCertificate.csクラスをダウンロードしました
  • このコードを使用して、.pfx証明書ファイルを生成しました。

    byte[] c = Certificate.CreateSelfSignCertificatePfx(
            "CN=yourhostname.com", //host name
            DateTime.Parse("2000-01-01"), //not valid before
            DateTime.Parse("2010-01-01"), //not valid after
            "mypassword"); //password to encrypt key file
    
        using (BinaryWriter binWriter = new BinaryWriter(
            File.Open(@"testcert.pfx", FileMode.Create)))
        {
            binWriter.Write(c);
        }
    

ステップ2:証明書をロードする

    X509Certificate cert = new X509Certificate2(
                            @"testcert.pfx", 
                            "mypassword");

ステップ3:それをまとめる

  • この非常に単純なSslStreamの例に基づいています
  • SslProtocolType列挙に関するコンパイル時エラーが発生します。これをSslProtocolType.DefaultからSslProtocols.Defaultに変更するだけです。
  • 非推奨の機能について3つの警告がありました。私はそれらすべてを提案された代替品と交換しました。
  • Server Program.csファイルのこの行を、手順2の行に置き換えました。

    X509Certificate cert = getServerCert();

  • Client Program.csファイルで、serverName = yourhostname.comを設定していることを確認してください(証明書の名前と一致していることを確認してください)。

  • Client Program.csでは、sslPolicyErrorsにRemoteCertificateChainErrorsが含まれているため、CertificateValidationCallback関数が失敗します。もう少し深く掘り下げると、これは、証明書に署名した発行機関が信頼されたルートではないためです。
  • ユーザーに証明書をルートストアなどにインポートさせたくないので、特別なケースを作成し、certificate.GetPublicKeyString()がファイルにある公開鍵と等しいことを確認します。そのサーバー用。一致する場合は、その関数からTrueを返します。それはうまくいくようです。

ステップ4:クライアント認証

クライアントの認証方法は次のとおりです(サーバーとは少し異なります)。

TcpClient client = new TcpClient();
client.Connect(hostName, port);

SslStream sslStream = new SslStream(client.GetStream(), false,
    new RemoteCertificateValidationCallback(CertificateValidationCallback),
    new LocalCertificateSelectionCallback(CertificateSelectionCallback));

bool authenticationPassed = true;
try
{
    string serverName = System.Environment.MachineName;

    X509Certificate cert = GetServerCert(SERVER_CERT_FILENAME, SERVER_CERT_PASSWORD);
    X509CertificateCollection certs = new X509CertificateCollection();
    certs.Add(cert);

    sslStream.AuthenticateAsClient(
        serverName,
        certs,
        SslProtocols.Default,
        false); // check cert revokation
}
catch (AuthenticationException)
{
    authenticationPassed = false;
}
if (authenticationPassed)
{
    //do stuff
}

CertificateValidationCallbackはサーバーの場合と同じですが、AuthenticateAsClientが1つの証明書だけでなく、証明書のコレクションを取得する方法に注意してください。したがって、次のようにLocalCertificateSelectionCallbackを追加する必要があります(この場合、クライアント証明書は1つしかないため、コレクションの最初の証明書を返すだけです)。

static X509Certificate CertificateSelectionCallback(object sender,
    string targetHost,
    X509CertificateCollection localCertificates,
    X509Certificate remoteCertificate,
    string[] acceptableIssuers)
{
    return localCertificates[0];
}
于 2009-03-31T03:42:31.553 に答える
2

あなたもこの例を見ることができます 非同期SslStreamクライアント/サーバー実装のサンプル http://blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx

証明書が正しく生成されない場合、例外が発生する可能性があります。サーバー モードの SSL では、関連付けられた秘密キーを持つ証明書を使用する必要があります。

基本的な証明書の例

makecert -sr LocalMachine -ss My -n CN=Test -sky exchange -sk 123456

また

外部ファイルとして

makecert -sr LocalMachine -ss My -n CN=Test -sky exchange -sk 123456 c:\Test.cer

証明書作成ツール (Makecert.exe)
http://msdn.microsoft.com/en-us/library/bfsktky3%28VS.80%29.aspx

于 2010-04-26T12:10:18.767 に答える
1

あなたが提案していることは、証明書を生成するためにコールバックが呼び出されるまで待つことを探しているように聞こえることを除いて、私には問題ないように聞こえます。それが飛ぶとは思わない。AFAIK、を呼び出すときに有効な証明書を提供する必要がありますAuthenticateAsX

ただし、これらのクラスはオーバーライド可能です。したがって、理論的には、最初に証明書を生成する必要があるかどうかを確認し、必要に応じてそれを生成してから、親AuthenticateAsXメソッドを呼び出す派生クラスを作成できます。

于 2009-03-30T02:11:47.473 に答える