2012-01-30 1 views
15

私は、アプリケーション内のいくつかの自己署名証明書を信頼する必要があるので、私はこのような検証コールバックをオーバーライドします。C#でServicePointManager.ServerCertificateValidationCallbackをオーバーライドするときにデフォルトの証明書チェックを呼び出す方法は?

ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback; 
... 

public static bool MyRemoteCertificateValidationCallback(
      Object sender, 
      X509Certificate certificate, 
      X509Chain chain, 
      SslPolicyErrors sslPolicyErrors) 
{ 

    if (sslPolicyErrors == SslPolicyErrors.None) 
     return true; 

    if (IsAprrovedByMyApplication(sender, certificate)) // <-- no matter what the check here is 
     return true; 
    else 
     return false; // <-- here I'd like to call the default Windwos handler rather than returning 'false' 
} 

しかし、ときそこにいくつかの政策の誤りをしている、と私が接続していますサイトはによって承認されていませんアプリケーションでは、例外がスローされます。 ここでの問題点は、Windowsの標準動作とは異なる点です。

は、このサイトを考えてみましょう:https://www.dscoduc.com/

ことの証明書が不明な発行者を持っているので、信頼できません。私はそれをMMCと共にLocal CopmuterのTrusted People(Windows 7)に追加しました。

私は、証明書の検証コールバックを上書きせずにこのコードを実行する場合:

HttpWebRequest http = (HttpWebRequest)HttpWebRequest.Create("https://www.dscoduc.com/"); 
using (WebResponse resp = http.GetResponse()) 
{ 
    using (StreamReader sr = new StreamReader(resp.GetResponseStream())) 
    { 
     string htmlpage = sr.ReadToEnd(); 
    } 
} 

それは正常に接続します。 これは、Windowsのデフォルトのバリデーターがこの証明書を信頼することを決定したことを意味します。

しかし、私はServerCertificateValidationCallbackを上書きしたら、私のコールバックがSslPolicyErrors.RemoteCertificateChainErrors とチェーンと呼ばれているが、ステータスを持つ1つの要素が含まれますX509ChainStatusFlags.PartialChain(私は現在のbecuase、ここにはエラーを受信しないことを期待するという事実に

このサイトは信頼できるリストには含まれていないため、コールバックから「true」を返すことは望ましくありません。 しかし、私は「偽」も返さないことを願っていません。または、「リモート証明書が検証手順に従って無効です」という例外が表示されます。https://www.dscoduc.com/には明らかに期待されていません。証明書コールバックがオーバーライドされていない場合、Windowsによって承認されます。 このサイトでは、Windowsでデフォルトの検証手順を実行します。 Windowsで既に実装されている(うまくいけばうまくいけば)ので、私はWindows Trustedストアを自分自身で調べ、すべてのチェーン要素を調べることは望ましくありません。

つまり、ユーザーが承認したサイト(自分の設定のどこかに保存されているサイト)を明示的に信頼し、他のすべてのユーザーに対してデフォルトの認証チェックを呼び出す必要があります。

ServicePointManager.ServerCertificateValidationCallbackのデフォルト値はnullです。したがって、後で呼び出すための 'デフォルト'コールバックはありません。 この「デフォルト」の証明書ハンドラをどのように呼び出す必要がありますか?

おかげ

答えて

6

それはあなたのコールバック内からチェーンを歩いて考えているより少ないことは困難です。

は、そのサンプル中http://msdn.microsoft.com/en-us/library/dd633677(v=exchg.80).aspx

見コードは、証明書が自己署名され、もしそうなら、それを信じるかどうか動作するように証明書チェーンを調べています。その代わりに、PartialChainを受け入れるようにそれを適応させることもできます。あなたはこのような何かを探しているはずだ:

また
if (status.Status == X509ChainStatusFlags.PartialChain || 
    (certificate.Subject == certificate.Issuer && 
    status.Status == X509ChainStatusFlags.UntrustedRoot) 
{ 
    // Certificates with a broken chain and 
    // self-signed certificates with an untrusted root are valid. 
    continue; 
} 
else if (status.Status != X509ChainStatusFlags.NoError) 
{ 
    // If there are any other errors in the certificate chain, 
    // the certificate is invalid, so the method returns false. 
    return false; 
} 

Subjectプロパティを調べる:このような

private static bool CertificateValidationCallBack(
    object sender, 
    System.Security.Cryptography.X509Certificates.X509Certificate certificate, 
    System.Security.Cryptography.X509Certificates.X509Chain chain, 
    System.Net.Security.SslPolicyErrors sslPolicyErrors) 
{ 
    return certificate.Subject.Contains(".dsoduc.com"); 
} 
3

何かがうまくいくかもしれません。 X509CertificateValidatorを使用すると、信頼できる人物ストアを検証に含めるかどうかを選択できます。

private static bool CertificateValidationCallBack(
    object sender, 
    X509Certificate certificate, 
    X509Chain chain, 
    SslPolicyErrors sslPolicyErrors) 
{ 
    // Your custom check here... 
    if (isYourSpecialCase) 
    { 
     return true; 
    } 

    // If it is not your special case then revert to default checks... 

    // Convert the certificate to a X509Certificate2 
    var certificate2 = certificate as X509Certificate2 ?? new X509Certificate2(certificate); 

    try 
    { 
     // Choose the type of certificate validation you want 
     X509CertificateValidator.PeerOrChainTrust.Validate(certificate2); 
     //X509CertificateValidator.ChainTrust.Validate(certificate2); 
    } 
    catch 
    { 
     return false; 
    } 

    // Sender is always either a WebReqest or a hostname string 
    var request = sender as WebRequest; 
    string requestHostname = request != null ? request.RequestUri.Host : (string)sender; 

    // Get the hostname from the certificate 
    string certHostname = certificate2.GetNameInfo(X509NameType.DnsName, false); 

    return requestHostname.Equals(certHostname, StringComparison.InvariantCultureIgnoreCase); 
} 
関連する問題