如何从客户端通过Web服务发送X509证书?

问题描述:

很显然,我在较早的帖子中提出了错误的问题。我有一个通过X.509证书保护的Web服务,它作为安全网站( https://。。 )。我想使用公司的根CA颁发的客户端计算机证书(也称为X.509)来向服务器验证客户端计算机是否有权使用该服务。为此,我需要检查证书并查找一些识别功能,并将其与数据库中存储的值(也许是指纹)相匹配。

Apparently I was asking the wrong question in my earlier post. I have a web service secured with a X.509 certificate, running as a secure web site (https://...). I want to use the client's machine certificate (also X.509) issued by the company's root CA to verify to the server that the client machine is authorized to use the service. In order to do this, I need to inspect the certificate and look for some identifying feature and match that to a value stored in a database (maybe the Thumbprint?).

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

Here is the code I use to get the certificate from the local certificate store (lifted straight from 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(); }
    }

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

Then, I attach the certificate to the outbound stream thusly:

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...
    }
}

我的问题是-如何在Web服务代码中获取证书?我碰到的大多数示例代码片段都介绍了如何进行自定义验证,其中似乎有一个GetCertificate()调用,显然,假设该部分非常容易,每个人都应该知道该怎么做?

My question is this -- how do I "get" the certificate in the web service code? Most sample code snippets I have come across that cover how to do custom validation have a GetCertificate() call in there, apparently assuming that part is so easy everyone should know how to do it?

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

My main class inherits from WebService, so I can use Context.Request.ClientCertificate to get a certificate, but that's an HttpClientCertificate, not an X509Certificate2. HttpContext gives me the same result. Other approaches all use web configuration code to call pre-defined verification code, with no clue as to how to call a custom C# method to do the verification.

我记得做过类似的事情,但是已经有一段时间了,但是,您是否在Web服务中尝试过此操作:

I recall doing something similar, its been awhile but, have you tried this in your web service:

X509Certificate2 cert = new X509Certificate2(Context.Request.ClientCertificate.Certificate);