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?