SQL Server 2008 R2 Express + Certificado SSL Wildcard

5

Certificados curinga (por exemplo, * .example.com) simplesmente não funcionavam no SQL Server 2008 ou inferior. Mas Criptografando conexões com o SQL Server nos estados do MSDN, simples como dia,

SQL Server 2008 R2 supports wildcards certificates.

Excelente. Então eu configurei o SQL Server 2008 R2 Express em uma máquina, e configurei a entrada HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\MSSQLServer\SuperSocketNetLib\Certificate para a impressão digital do meu certificado SSL curinga (porque em cinco anos lidando com SQL Server, eu nunca obtive aquele diálogo # $ @ # na Configuração do Sql Server para exibir quaisquer certificados).

O log do SQL Server me diz que isso foi muito bem:

2010-08-31 11:46:04.04 Server The certificate [Cert Hash(sha1) "5DDD9E51B30E0CA6CE3656AE54EC6D0B8B75904A"] was successfully loaded for encryption.

Infelizmente, se eu tentar usar o Microsoft SQL Server Management Studio (a versão 2008 R2) ou as classes Sql * fornecidas no .NET Framework 4.0, sempre receberei a seguinte exceção:

A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: SSL Provider, error: 0 - The certificate's CN name does not match the passed value.) (Microsoft SQL Server, Error: -2146762481)

Aqui estão as coisas que eu tentei:

  • Certificando-se de que o nome do host esteja configurado corretamente. (Por exemplo, o nome do host é prod e o sufixo DNS está definido corretamente: prod.example.com .)
  • Certificar-se de que um registro PTR para prod.example.com esteja configurado corretamente.
  • Definindo TrustServerCertificate=Yes na cadeia de conexão.

Curiosamente, se eu tentar conectar via sqlcmd.exe , não receberei reclamações sobre o certificado.

Estou começando a suspeitar que os certificados curinga no servidor SQL serão carregados pelo servidor, mas não há nenhuma instância do cliente SQL .NET que possa funcionar corretamente contra um.

Alguém pode lançar alguma luz sobre isso?

Atualizar : algumas informações adicionais sobre o certificado curinga:

  • Sim, está instalado no Computador local > Pessoal > Certificados.
  • Ele tem o uso avançado de chave Server Authentication (1.3.6.1.5.5.7.3.1) .
  • Tem Key Encipherment (a0) , em que (a0) significa AT_KEYEXCHANGE . (Funciona bem para um servidor FTP e um site do IIS, portanto, se isso estivesse estragado, imagino que não funcionaria lá.)
  • O assunto do certificado é CN = *.example.com (substituindo "exemplo" pelo nosso domínio de trabalho). Ou seja, é emitido para *.example.com . Este foi o dealbreaker nas versões anteriores ao 2008 R2 que impedia que o SQL Server carregasse o certificado.
  • Tem a chave privada.
  • O Nome Amigável pode ser definido como o que for - prod.example.com é o que é agora.

Atualização 2 : Então isso vai realmente fritar seu cérebro:

Se eu configurar uma conexão via ODBC:

Versão do cliente nativo do Microsoft SQL Server 10.50.1600

Data Source Name: prod.example.com
Data Source Description: prod
Server: tcp:prod.example.com,8484\SQLEXPRESS
Use Integrated Security: No
Database: (Default)
Language: (Default)
Data Encryption: Yes
Trust Server Certificate: No
Multiple Active Result Sets(MARS): No
Translate Character Data: Yes
Log Long Running Queries: No
Log Driver Statistics: No
Use Regional Settings: No
Use ANSI Quoted Identifiers: Yes
Use ANSI Null, Paddings and Warnings: Yes

Depois, obtenho um resultado bem-sucedido:

Microsoft SQL Server Native Client Version 10.50.1600

Running connectivity tests...

Attempting connection
Connection established
Verifying option settings
INFO: Connection was encrypted with server certificate validation.
Disconnecting from server

TESTS COMPLETED SUCCESSFULLY!

Atualização 3 : OK, uma última tentativa antes de eu desistir do certificado curinga. Aqui está um pequeno programa de amostra que eu escrevi em C #:

    static void Main(string[] args)
    {
        Console.WriteLine(new string('-', 40));

        try
        {
            var connectionString = 
                @"Data Source=tcp:prod.example.com,8484\SQLEXPRESS; " +
                "User ID=ExampleDev;Password=ExamplePass; " +
                "Encrypt=True";

            Console.WriteLine("Trying SqlConnection...");

            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();

                Console.WriteLine("SUCCESS!");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("FAILED!");
            Console.WriteLine(e);
        }

        Console.WriteLine(new string('-', 40));

        try
        {
            var connectionString = 
                @"Driver={SQL Server Native Client 10.0}; " +
                "Server=tcp:prod.example.com,8484\SQLEXPRESS; " +
                "Uid=ExampleDev; Pwd=ExamplePass; Encrypt=yes";

            Console.WriteLine("Trying OdbcConnection...");

            using (var connection = new OdbcConnection(connectionString))
            {
                connection.Open();

                Console.WriteLine("SUCCESS!");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("FAILED!");
            Console.WriteLine(e);
        }

        Console.WriteLine(new string('-', 40));
        Console.ReadLine();
    }
}

A saída deste programa, após a substituição de nomes de usuário e senhas, conforme apropriado, como executado na minha máquina, é a seguinte:

----------------------------------------
Trying SqlConnection...
FAILED!
System.Data.SqlClient.SqlException (0x80131904): A connection was successfully e
stablished with the server, but then an error occurred during the pre-login hand
shake. (provider: SSL Provider, error: 0 - The certificate's CN name does not ma
tch the passed value.)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception
, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParser.ConsumePreLoginHandshake(Boolean encrypt,
Boolean trustServerCert, Boolean& marsCapable)
   at System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternal
ConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Bool
ean encrypt, Boolean trustServerCert, Boolean integratedSecurity)
   >
----------------------------------------
Trying OdbcConnection...
SUCCESS!
----------------------------------------

É por isso que eu bebo.

Eu sei que "select geralmente não está quebrado", mas eu não sei o que fazer com isso. Parece que as classes SqlClient no .NET Framework 4.0 estão quebradas quando se trata de validar certificados curinga. O que mais pode ser diferente entre os dois métodos?

    
por Nicholas Piasecki 31.08.2010 / 18:40

2 respostas

3

O fato de o certificado não ter sido exibido na Ferramenta de configuração apresenta o primeiro problema. Se o certificado estiver instalado corretamente, ele deverá aparecer nessa lista. Onde no armazenamento de certificados você colocou o certificado? Deve estar no armazenamento de certificados do computador local em Personal > Certificados.

Você também precisará verificar se o certificado de autenticação do servidor possui a propriedade Uso Avançado de Chave do certificado para especificar a Autenticação do Servidor (1.3.6.1.5.5.7.3.1). O certificado também deve ser criado usando a opção KeySpec de AT_KEYEXCHANGE, você pode, opcionalmente, configurar a propriedade de uso de chave para incluir a codificação de chave.

    
por 31.08.2010 / 20:25
1

A resposta da Microsoft é que o .NET SqlClient não funcionará com certificados curinga, ponto final.

Embora o SQL Server 2008 R2 Express agora ofereça suporte a certificados curinga, e os provedores nativos foram atualizados para entendê-los (isso significa ODBC e OLEDB), as classes System.Data.SqlClient no .NET Framework 4.0.

Essencialmente, isso significa que, se você estiver dando suporte a um aplicativo .NET no servidor de banco de dados, o recurso de curingas ainda não será executado.

    
por 03.09.2010 / 00:28