Программная установка списка отзыва сертификатов C #

Я использую C # / WCF. У меня есть веб-служба, которую должен вызывать клиент. Это определение службы:

<service behaviorConfiguration="WCFInterface.CommonBehavior" name="WCFInterface.Content">
  <endpoint address="" binding="ws2007HttpBinding" bindingConfiguration="wsHttpUserName"
 contract="ABB.fTunes.WCFInterface.IContent">
    <identity>
      <dns value="fTunesTestServer" />
    </identity>
  </endpoint>
  <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>

А это привязка:

<ws2007HttpBinding>
  <binding name="wsHttpUserName">
    <security mode="Message">
      <message clientCredentialType="UserName"/>
    </security>
  </binding>
</ws2007HttpBinding>

Если я правильно понимаю, сообщения, отправляемые с сервера на клиент, зашифрованы с помощью сертификата. В настоящее время я все еще работаю с сертификатами разработчика. Я создал корневой сертификат, список отзыва сертификатов и ключ на сервере.

Я устанавливаю клиент с помощью установщика Windows, и у меня есть настраиваемое действие установки для установки сертификатов.

Следующий код показывает, как сертификаты добавляются в магазин.

Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ClientCertificates.MyRoot.cer");
byte[] buffer = new byte[((int)(manifestResourceStream.Length - 1L)) + 1];
manifestResourceStream.Read(buffer, 0, (int)manifestResourceStream.Length);
manifestResourceStream.Close();

var cert = new X509Certificate2(buffer);
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();

/*
// The CRL is also needed, no idea why
manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ClientCertificates.MyRoot.crl");
buffer = new byte[((int)(manifestResourceStream.Length - 1L)) + 1];
manifestResourceStream.Read(buffer, 0, (int)manifestResourceStream.Length);
manifestResourceStream.Close();
cert = new X509Certificate2(buffer);
store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();
*/

// This is the key 
manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ClientCertificates.MyTestServer.cer");
buffer = new byte[((int)(manifestResourceStream.Length - 1L)) + 1];
manifestResourceStream.Read(buffer, 0, (int)manifestResourceStream.Length);
manifestResourceStream.Close();

cert = new X509Certificate2(buffer);
store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();

Теперь у меня два варианта поведения: установка сертификатов работает, но когда я вызываю веб-службу, я получаю SecurityNegotiationException. Когда я добавляю список отозванных сертификатов вручную, связь с сервером работает. Когда я пытаюсь сделать это программно (см. Код выше), это не работает. Я получаю исключение «Не удалось найти запрошенный объект».

Я пытался использовать разные магазины, но безуспешно.

У меня два вопроса: а) Зачем мне нужен CRL на клиенте? б) Если нужно, как программно установить? Где моя ошибка выше?

Спасибо за помощь, Кей


person Community    schedule 25.09.2009    source источник


Ответы (3)


Как правило, CRL должен быть доступен в Интернете и загружаться с URL отзыва, указанного в сертификате сервера. Я не знаю, есть ли внеполосный механизм для его получения, но даже если бы он был, это как бы свело на нет цель (позволяя клиентам обнаружить, что сертификат сервера был скомпрометирован / отозван). Тем не менее, CRL действительно избыточен для самоподписанных сертификатов, если вы не используете сертификат для реальной взаимной аутентификации и не беспокоитесь о том, что ключ будет скомпрометирован (в этом случае купите коммерческий сертификат и позвольте им разобраться с ним) .

Если вы не можете получить сертификат, созданный без URL-адреса отзыва, я бы рекомендовал полностью отключить клиентскую проверку CRL, если он вам действительно не нужен. Вы можете сделать это, добавив следующее в app.config клиента веб-сервиса:

  <system.net>
    <settings>
      <servicePointManager checkCertificateRevocationList="false"/>
    </settings>
  </system.net>

Если вы используете WCF, вам может потребоваться связать его с clientCredentials endpointBehavior в разделе serviceCertificate-> revocationMode: NoCheck.

person nitzmahone    schedule 26.09.2009

Способы автоматизации установки списка отзыва сертификатов, в том числе с помощью кода C #, можно найти здесь: Программная установка списка отзыва сертификатов (CRL)

person davmos    schedule 21.10.2013

Для этого нам нужно использовать только Win32 Apis. Для этого не существует первоклассных системных API C #.

public class CRLHandler
{
    private const int CERT_STORE_PROV_SYSTEM = 10;
    private const int CERT_SYSTEM_STORE_LOCAL_MACHINE = (2 << 16);

    public const int X509_ASN_ENCODING = 0x00000001;
    public const int PKCS_7_ASN_ENCODING = 0x00010000;

    public const int CERT_STORE_ADD_REPLACE_EXISTING = 3;

    [DllImport("CRYPT32.DLL", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CertOpenStore(
      int storeProvider,
      int encodingType,
      IntPtr hcryptProv,
      int flags,
      string pvPara);

    [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr CertCreateCRLContext(
        int dwCertEncodingType,
        byte[] pbCrlEncoded,
        int cbCrlEncoded);

    [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool CertAddCRLContextToStore(
      IntPtr hCertStore,
      IntPtr pCertContext,
      uint dwAddDisposition,
      IntPtr ppStoreContext);

    [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool CertFreeCRLContext(
        IntPtr pCrlContext);

    public void AddOrUpdateCRLToStore(string crlString)
    {
        IntPtr crlContext = IntPtr.Zero;
        try
        {
            byte[] rawData = Convert.FromBase64String(crlString);

            IntPtr hLocalCertStore = CertOpenStore(
                  CERT_STORE_PROV_SYSTEM,
                  0,
                  IntPtr.Zero,
                  CERT_SYSTEM_STORE_LOCAL_MACHINE,
                  "CA");

            crlContext = CertCreateCRLContext(
                X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                rawData,
                rawData.Length);

            if (crlContext == IntPtr.Zero)
            {
                string error = "AddOrUpdateCRLToStore - CertCreateCRLContext error #" + Marshal.GetLastWin32Error();
                throw new Exception(error);
            }

            bool crlAddResult = CertAddCRLContextToStore(
                hLocalCertStore, crlContext, CERT_STORE_ADD_REPLACE_EXISTING, IntPtr.Zero);

            if (!crlAddResult)

            {
                string error = "AddOrUpdateCRLToStore - CertAddCRLContextToStore #" + Marshal.GetLastWin32Error();
                throw new Exception(error);
            }
        }
        finally
        {
            if(crlContext != IntPtr.Zero)
            {
                CertFreeCRLContext(crlContext);
            }
        }
    }
}

Метод AddOrUpdateCRLToStore принимает строку crl в кодировке base64 (без заголовка и поставщика), а затем импортирует crl в хранилище CA на локальном компьютере.

Чтобы изменить значения, такие как локальный компьютер, хранилище сертификатов в этом API см. Здесь

person saravanan    schedule 03.06.2021