Как получить сертификат X509, отправленный с клиента в веб-сервисе? - PullRequest
10 голосов
/ 21 мая 2009

Видимо, я задавал неправильный вопрос в моем предыдущем посте. У меня есть веб-служба, защищенная сертификатом X.509 и работающая как защищенный веб-сайт ( https: //...). Я хочу использовать сертификат компьютера клиента (также 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 дает мне тот же результат. Все другие подходы используют код веб-конфигурации для вызова предварительно определенного кода проверки, не имея понятия, как вызвать пользовательский метод C # для выполнения проверки.

Ответы [ 2 ]

13 голосов
/ 21 мая 2009

Я помню, что делал нечто подобное, это было какое-то время, но вы пробовали это в своем веб-сервисе:

X509Certificate2 cert = new X509Certificate2(Context.Request.ClientCertificate.Certificate);
1 голос
/ 01 октября 2009

Что касается того, как привязать сертификат обратно к пользователю, при условии, что идентификация пользователя, связанного с ключом, является хорошей (поскольку сертификат был проверен обратно в доверенный корень и не был отозван), тогда вы необходимо привязать удостоверение личности, заявленное сертификатом для пользователя. Вы можете просто использовать строковую форму LDAP субъектного DN и посмотреть его (cn = Имя пользователя, ou = Department ...), чтобы определить локальный идентификатор. Это устойчиво в случае, если пользователь повторно генерирует свой ключ / сертификат, например, из-за потери карты или естественного истечения срока действия сертификата. Это основано на том факте, что два центра сертификации не будут выдавать два сертификата с одинаковым именем субъекта двум разным людям.

Если сертификат был выдан MS CA, в нем может быть имя участника-пользователя, которое фактически является именем входа в домен.

В качестве альтернативы, если вы хотите привязать удостоверение пользователя к фактическому сертификату, обычным способом является сохранение имени эмитента и серийного номера сертификата. Центры сертификации должны выдавать уникальные серийные номера для каждого сертификата. Обратите внимание, серийные номера могут быть большими в зависимости от CA. Тем не менее, это означает, что использование этого метода означает, что данные сертификата в базе данных должны обновляться каждый раз при повторном выдаче сертификата пользователя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...