11

显然我在之前的帖子中问了错误的问题。我有一个使用 X.509 证书保护的 Web 服务,作为安全网站 ( https://... ) 运行。我想使用公司根 CA 颁发的客户端机器证书(也是 X.509)向服务器验证客户端机器是否有权使用该服务。为此,我需要检查证书并寻找一些识别特征并将其与存储在数据库中的值(可能是指纹?)相匹配。

这是我用来从本地证书存储区获取证书的代码(直接来自http://msdn.microsoft.com/en-us/magazine/cc163454.aspx):

 public static class SecurityCertificate
{
    private static X509Certificate2 _certificate = null;

    public static X509Certificate2 Certificate
    {
        get { return _certificate; }
    }

    public static bool LoadCertificate()
    {
        // get thumbprint from app.config
        string thumbPrint = Properties.Settings.Default.Thumbprint;
        if ( string.IsNullOrEmpty( thumbPrint ) )
        {
            // if no thumbprint on file, user must select certificate to use
            _certificate = PickCertificate( StoreLocation.LocalMachine, StoreName.My );
            if ( null != _certificate )
            {
                // show certificate details dialog
                X509Certificate2UI.DisplayCertificate( _certificate );
                Properties.Settings.Default.Thumbprint = _certificate.Thumbprint;
                Properties.Settings.Default.Save();
            }
        }
        else
        {
            _certificate = FindCertificate( StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, thumbPrint );
        }

        if ( null == _certificate )
        {
            MessageBox.Show( "You must have a valid machine certificate to use STS." );
            return false;
        }

        return true;
    }

    private static X509Certificate2 PickCertificate( StoreLocation location, StoreName name )
    {
        X509Store store = new X509Store( name, location );
        try
        {
            // create and open store for read-only access
            store.Open( OpenFlags.ReadOnly );

            X509Certificate2Collection coll = store.Certificates.Find( X509FindType.FindByIssuerName, STSClientConstants.NBCCA, true );
            if ( 0 == coll.Count )
            {
                MessageBox.Show( "No valid machine certificate found - please contact tech support." );
                return null;
            }

            // pick a certificate from the store
            coll = null;
            while ( null == coll || 0 == coll.Count )
            {
                coll = X509Certificate2UI.SelectFromCollection(
                        store.Certificates, "Local Machine Certificates",
                        "Select one", X509SelectionFlag.SingleSelection );
            }

            // return first certificate found
            return coll[ 0 ];
        }
        // always close the store
        finally { store.Close(); }
    }

    private static X509Certificate2 FindCertificate( StoreLocation location, StoreName name, X509FindType findType, string findValue )
    {
        X509Store store = new X509Store( name, location );
        try
        {
            // create and open store for read-only access
            store.Open( OpenFlags.ReadOnly );

            // search store
            X509Certificate2Collection col = store.Certificates.Find( findType, findValue, true );

            // return first certificate found
            return col[ 0 ];
        }
        // always close the store
        finally { store.Close(); }
    }

然后,我将证书附加到出站流中:

public static class ServiceDataAccess
{    
    private static STSWebService _stsWebService = new STSWebService();

    public static DataSet GetData(Dictionary<string,string> DictParam, string action)
    {
        // add the machine certificate here, the first web service call made by the program (only called once)
        _stsWebService.ClientCertificates.Add( SecurityCertificate.Certificate );
        // rest of web service call here...
    }
}

我的问题是——我如何“获取”网络服务代码中的证书?我遇到的大多数示例代码片段都涵盖了如何进行自定义验证,其中有一个 GetCertificate() 调用,显然假设这部分很容易每个人都应该知道怎么做?

我的主类继承自 WebService,所以我可以使用 Context.Request.ClientCertificate 来获取证书,但那是 HttpClientCertificate,而不是 X509Certificate2。HttpContext 给了我同样的结果。其他方式都是使用web配置代码调用预定义的验证码,不知道如何调用自定义的C#方法进行验证。

4

2 回答 2

14

我记得做过类似的事情,已经有一段时间了,但是你有没有在你的网络服务中尝试过这个:

X509Certificate2 cert = new X509Certificate2(Context.Request.ClientCertificate.Certificate);
于 2009-05-21T17:49:29.263 回答
2

关于如何将证书绑定回用户的主题,因此假设与密钥关联的用户的身份是好的(因为证书已被验证回受信任的根并且尚未被撤销),那么您需要绑定证书向用户声明的身份。您可以只使用主题 DN 的 LDAP 字符串形式并查找 (cn=Username,ou=Department...) 以确定本地 ID。这在用户重新生成他们的密钥/证书的情况下是有弹性的,比如由于卡丢失或证书自然到期。这取决于这样一个事实,即两个 CA 不会向两个不同的人颁发两个具有相同主题名称的证书。

如果证书是由 MS CA 颁发的,则它可能有一个 UPN,它实际上是一个域登录名。

或者,如果您想将用户的身份与实际证书相关联,通常的方法是存储颁发者名称和证书序列号。CA 必须为每个证书颁发唯一的序列号。注意序列号可能很大,具体取决于 CA。然而,使用此方法并不意味着每次重新颁发用户证书时都必须更新数据库中的证书详细信息。

于 2009-10-01T01:29:32.357 回答