Schannel
O pacote de segurança do Canal Seguro (Schannel), cujo identificador de serviço de autenticação é RPC_C_AUTHN_GSS_SCHANNEL, dá suporte aos seguintes protocolos baseados em chave pública: SSL (Secure Sockets Layer) versões 2.0 e 3.0, TLS (Transport Layer Security) 1.0 e PCT (Private Communication Technology) 1.0. O TLS 1.0 é uma versão padronizada e ligeiramente modificada do SSL 3.0 emitida pela IETF (Internet Engineering Task Force) em janeiro de 1999, no documento RFC 2246. Como o TLS foi padronizado, os desenvolvedores são incentivados a usar o TLS em vez de SSL. O PCT é incluído apenas para compatibilidade com versões anteriores e não deve ser usado para o novo desenvolvimento. Quando o pacote de segurança Schannel é usado, o DCOM negocia automaticamente o melhor protocolo, dependendo dos recursos do cliente e do servidor.
Os tópicos a seguir descrevem brevemente o protocolo TLS e como ele funciona com o DCOM.
- Quando usar TLS
- breve visão geral de como o TLS funciona
- certificados X.509
-
usando TLS em COM
- como um servidor define o de cobertor de segurança
- como um cliente define o cobertor de segurança
- como um cliente altera o de cobertor de segurança
- exemplo: o cliente altera o do Cobertor de Segurança
- tópicos relacionados
Nota
Todas as informações sobre o protocolo TLS nestas seções também se aplicam aos protocolos SSL e PCT.
Quando usar o TLS
O TLS é a única opção de segurança disponível quando os servidores precisam provar sua identidade para clientes anônimos. Isso é particularmente importante para sites que desejam participar do comércio eletrônico porque ajuda a proteger a transmissão de informações confidenciais, como números de cartão de crédito. O TLS garante que os clientes de comércio eletrônico podem ter certeza de com quem estão fazendo negócios porque recebem uma prova da identidade do servidor. Ele também fornece ao servidor de comércio eletrônico a eficiência de não precisar se preocupar em autenticar a identidade de cada um de seus clientes.
O TLS requer que todos os servidores provem sua identidade para os clientes. Além disso, o TLS fornece a opção de fazer com que os clientes provem sua identidade para os servidores. Essa autenticação mútua pode ser útil para restringir o acesso de determinadas páginas da Web em uma intranet corporativa grande.
O TLS dá suporte aos níveis de autenticação mais fortes e oferece uma arquitetura aberta que permite que a força de criptografia aumente ao longo do tempo para acompanhar a inovação tecnológica. O TLS é a melhor opção para ambientes em que o nível mais alto de segurança é desejado para os dados em trânsito.
Breve visão geral de como o TLS funciona
O TLS é baseado em uma PKI (infraestrutura de chave pública), que usa pares de chaves públicas/privadas para habilitar a criptografia de dados e estabelecer a integridade de dados e usa certificados X.509 para autenticação.
Muitos protocolos de segurança, como o protocolo Kerberos v5, dependem de uma única chave para criptografar e descriptografar dados. Portanto, esses protocolos dependem da troca segura de chaves de criptografia; no protocolo Kerberos, isso é feito por meio de tíquetes obtidos do KDC (Centro de Distribuição de Chaves). Isso exige que todos que usam o protocolo Kerberos sejam registrados com o KDC, o que seria uma limitação impraticável para um servidor Web de comércio eletrônico destinado a atrair milhões de clientes de todo o mundo. O TLS, portanto, depende de uma PKI, que usa duas chaves para criptografia de dados"quando uma chave do par criptografa os dados, somente a outra chave do par pode descriptografá-los. O principal benefício desse design é que a criptografia pode ser executada sem exigir a troca segura de chaves de criptografia.
Uma PKI usa uma técnica em que uma das chaves é mantida privada e está disponível apenas para a entidade de segurança a quem está registrada, enquanto a outra chave é tornada pública para qualquer pessoa acessar. Se alguém quiser enviar uma mensagem privada ao proprietário de um par de chaves, a mensagem poderá ser criptografada com a chave pública e somente a chave privada poderá ser usada para descriptografar a mensagem.
Pares de chaves também são usados para verificar a integridade dos dados que estão sendo enviados. Para fazer isso, o proprietário do par de chaves pode anexar uma assinatura digital aos dados antes de enviá-la. Criar uma assinatura digital envolve calcular um hash dos dados e criptografar o hash com a chave privada. Qualquer pessoa que use a chave pública para descriptografar a assinatura digital tem a certeza de que a assinatura digital deve ter vindo apenas da pessoa que possui a chave privada. Além disso, o destinatário pode calcular um hash dos dados usando o mesmo algoritmo que o remetente e, se o hash calculado corresponder ao enviado na assinatura digital, o destinatário poderá ter certeza de que os dados não foram modificados depois que foram assinados digitalmente.
Uma desvantagem de usar uma PKI para criptografia de dados de alto volume é seu desempenho relativamente lento. Devido à matemática intensiva envolvida, a criptografia e a descriptografia de dados usando uma criptografia assimétrica que depende de um par de chaves podem ser até 1.000 vezes mais lentas do que a criptografia e a descriptografia usando uma criptografia simétrica que depende apenas de uma única chave. O TLS, portanto, usa uma PKI apenas para gerar assinaturas digitais e para negociar a chave única específica da sessão que será usada pelo cliente e pelo servidor para criptografia e descriptografia de dados em massa. O TLS dá suporte a uma ampla variedade de criptografias simétricas de chave única e criptografias adicionais podem ser adicionadas no futuro.
Para obter mais informações sobre o protocolo de handshake do TLS, consulte protocolo TLS Handshake Protocol.
Para obter mais detalhes sobre a criptografia por trás do protocolo TLS, consulte Cryptography Essentials.
Certificados X.509
Um problema crítico que deve ser tratado por uma PKI é a capacidade de confiar na autenticidade da chave pública que está sendo usada. Quando você usa uma chave pública emitida para uma empresa com a qual você deseja fazer negócios, você quer ter certeza de que a chave realmente pertence à empresa em vez de a um ladrão que quer descobrir o número do seu cartão de crédito.
Para garantir a identidade de uma entidade de segurança que contém um par de chaves, a entidade de segurança recebe um certificado X.509 por uma AC (autoridade de certificação). Esse certificado contém informações que identificam a entidade de segurança, contêm a chave pública da entidade de segurança e é assinado digitalmente pela AC. Essa assinatura digital indica que a AC acredita que a chave pública contida no certificado pertence verdadeiramente à entidade de segurança identificada pelo certificado.
E como você confia na AC? Como a ac em si contém um certificado X.509 que foi assinado por uma AC de nível superior. Essa cadeia de assinaturas de certificado continua até atingir uma AC raiz, que é uma AC que assina seus próprios certificados. Se você confiar na integridade da AC raiz de um certificado, poderá confiar na autenticidade do próprio certificado. Portanto, escolher CAs raiz em que você está disposto a confiar é um dever importante para um administrador do sistema.
Certificados do cliente
Quando os protocolos de camada de transporte de segurança surgiram pela primeira vez, sua principal finalidade era garantir que um cliente estava se conectando a um servidor autêntico e ajudar a proteger a privacidade dos dados enquanto estava em trânsito. No entanto, o SSL 3.0 e o TLS 1.0 também incluem suporte para a transmissão do certificado de um cliente durante o handshake do protocolo. Esse recurso opcional permite a autenticação mútua do cliente e do servidor.
A decisão de usar um certificado do cliente deve ser tomada no contexto do aplicativo. Os certificados do cliente serão desnecessários se o requisito principal estiver autenticando o servidor. No entanto, se a autenticação do cliente for essencial, o certificado de um cliente poderá ser usado em vez de depender da autenticação personalizada dentro do aplicativo. O uso de certificados de cliente é preferível em vez da autenticação personalizada, pois oferece aos usuários um cenário de logon único.
Usando o TLS em COM
O TLS dá suporte apenas ao nível de representação (RPC_C_IMP_LEVEL_IMPERSONATE) de representação. Se o COM negociar o TLS como o serviço de autenticação em um proxy, COM definirá o nível de representação para representar, independentemente do padrão do processo. Para que a representação funcione corretamente no TLS, o cliente deve fornecer um certificado X.509 ao servidor e o servidor deve ter esse certificado mapeado para uma conta de usuário específica no servidor. Para obter mais informações, consulte o guia passo a passo para mapear certificados para contas de usuário.
O TLS não dá suporte a de camuflagem. Se um sinalizador de camuflagem e TLS forem especificados em um CoInitializeSecurity ou uma chamada IClientSecurity::SetBlanket, E_INVALIDARG será retornado.
O TLS não funciona com o nível de autenticação definido como Nenhum. O handshake entre o cliente e o servidor examina o nível de autenticação definido por cada um e escolhe a configuração de segurança mais alta para a conexão.
Os parâmetros de segurança do TLS podem ser definidos chamando CoInitializeSecurity e CoSetProxyBlanket. As seções a seguir descrevem as nuances envolvidas na realização dessas chamadas.
Como um servidor define o cobertor de segurança
Se um servidor quiser usar o TLS, ele deverá especificar Schannel (RPC_C_AUTHN_GSS_SCHANNEL) como um serviço de autenticação no parâmetro asAuthSvc do CoInitializeSecurity. Para impedir que os clientes se conectem ao servidor usando um serviço de autenticação menos seguro, o servidor deve especificar apenas o Schannel como um serviço de autenticação quando chama CoInitializeSecurity. O servidor não pode alterar o cobertor de segurança depois de ter chamado CoInitializeSecurity.
Para usar o TLS, os seguintes parâmetros devem ser especificados quando um servidor chama CoInitializeSecurity:
- pVoid deve ser um ponteiro para um objetoIAccessControlou um ponteiro para um SECURITY_DESCRIPTOR. Ele não deve ser NULL ou um ponteiro para uma AppID.
- cAuthSvc não pode ser 0 ou -1. Os servidores COM nunca escolhem schannel quando cAuthSvc é -1.
-
asAuthSvc deve especificar o Schannel como um possível serviço de autenticação. Isso é feito definindo os seguintes parâmetros de SOLE_AUTHENTICATION_SERVICE para o membro Schannel do SOLE_AUTHENTICATION_LIST:
- dwAuthnSvc deve ser RPC_C_AUTHN_GSS_SCHANNEL.
- dwAuthzSvc deve ser RPC_C_AUTHZ_NONE. Atualmente, ele é ignorado.
- pPrincipalName deve ser um ponteiro para um CERT_CONTEXT, convertido como um ponteiro para OLECHAR, que representa o certificado X.509 do servidor.
- dwAuthnLevel indica o nível mínimo de autenticação que será aceito dos clientes para uma conexão bem-sucedida. Não pode ser RPC_C_AUTHN_LEVEL_NONE.
- dwCapabilities não deve ter o sinalizador EOAC_APPID definido. O sinalizador EOAC_ACCESS_CONTROL deverá ser definido se pVoid apontar para um objetoIAccessControl; ele não deve ser definido se pVoid aponta para um SECURITY_DESCRIPTOR. Para outros sinalizadores que podem ser definidos, consulte CoInitializeSecurity.
Para obter mais informações sobre como usar CoInitializeSecurity, consulte Setting Processwide Security with CoInitializeSecurity.
Como um cliente define o cobertor de segurança
Se um cliente quiser usar o TLS, ele deverá especificar Schannel (RPC_C_AUTHN_GSS_SCHANNEL) em sua lista de serviços de autenticação no parâmetro pAuthList de CoInitializeSecurity. Se o Schannel não for especificado como um serviço de autenticação possível quando CoInitializeSecurity for chamado, uma chamada posterior para CoSetProxyBlanket (ou IClientSecurity::SetBlanket) falhará se tentar especificar Schannel como o serviço de autenticação.
Os seguintes parâmetros devem ser especificados quando um cliente chama CoInitializeSecurity:
- dwAuthnLevel especifica o nível de autenticação padrão que o cliente deseja usar. Não pode ser RPC_C_AUTHN_LEVEL_NONE.
- dwImpLevel deve ser RPC_C_IMP_LEVEL_IMPERSONATE.
-
pAuthList deve ter os seguintes parâmetros de SOLE_AUTHENTICATION_INFO como membro da lista:
- dwAuthnSvc deve ser RPC_C_AUTHN_GSS_SCHANNEL.
- dwAuthzSvc deve ser RPC_C_AUTHZ_NONE.
- pAuthInfo é um ponteiro para um CERT_CONTEXT, convertido como um ponteiro para nulo, que representa o certificado X.509 do cliente. Se o cliente não tiver um certificado ou não quiser apresentar seu certificado ao servidor, pAuthInfo deverá ser NULL e uma conexão anônima será tentada com o servidor.
- dwCapabilities é um conjunto de sinalizadores que indicam recursos adicionais do cliente. Consulte CoInitializeSecurity para obter informações sobre quais sinalizadores devem ser definidos.
Para obter mais informações sobre como usar CoInitializeSecurity, consulte Setting Processwide Security with CoInitializeSecurity.
Como um cliente altera o cobertor de segurança
Se um cliente quiser usar o TLS, mas alterar o cobertor de segurança depois de chamar CoInitializeSecurity, ele deverá chamar CoSetProxyBlanket ou IClientSecurity::SetBlanket com parâmetros semelhantes aos usados na chamada para CoInitializeSecurity, com as seguintes diferenças:
- pServerPrincName indica o nome principal do servidor, no formato msstd ou fullsic. Para obter informações sobre esses formatos, consulte Principais Nomes. Se o cliente tiver o certificado X.509 do servidor, ele poderá encontrar o nome principal chamando RpcCertGeneratePrincipalName.
- pAuthInfo é um ponteiro para um CERT_CONTEXT, convertido como um ponteiro para RPC_AUTH_IDENTITY_HANDLE, que representa o certificado X.509 do cliente. Se o cliente não tiver um certificado ou não quiser apresentar seu certificado ao servidor, pAuthInfo deverá ser NULL e uma conexão anônima será tentada com o servidor.
- dwCapabilities consiste em sinalizadores que indicam recursos adicionais do cliente. Somente quatro sinalizadores podem ser usados para alterar as configurações de cobertor de segurança: EOAC_DEFAULT, EOAC_MUTUAL_AUTH, EOAC_ANY_AUTHORITY (esse sinalizador foi preterido) e EOAC_MAKE_FULLSIC. Para obter mais informações, consulte CoSetProxyBlanket.
Para obter mais informações sobre como usar CoSetProxyBlanket, consulte Configuração de Segurança no Nível do Proxy de Interface.
Exemplo: o cliente altera o cobertor de segurança
O exemplo a seguir demonstra como um cliente pode alterar o cobertor de segurança para acomodar uma solicitação do servidor para que o cliente forneça seu certificado X.509. O código de tratamento de erros é omitido para fins de brevidade.
void ClientChangesSecurity ()
{
HCRYPTPROV provider = 0;
HCERTSTORE cert_store = NULL;
PCCERT_CONTEXT client_cert = NULL;
PCCERT_CONTEXT server_cert = NULL;
WCHAR *server_princ_name = NULL;
ISecret *pSecret = NULL;
MULTI_QI server_instance;
COSERVERINFO server_machine;
SOLE_AUTHENTICATION_LIST auth_list;
SOLE_AUTHENTICATION_INFO auth_info[1];
// Specify all the authentication info.
// The client is willing to connect using SChannel,
// with no client certificate.
auth_list.cAuthInfo = 1;
auth_list.aAuthInfo = auth_info;
auth_info[0].dwAuthnSvc = RPC_C_AUTHN_GSS_SCHANNEL;
auth_info[0].dwAuthzSvc = RPC_C_AUTHZ_NONE;
auth_info[0].pAuthInfo = NULL; // No certificate
// Initialize client security with no client certificate.
CoInitializeSecurity( NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE, &auth_list,
EOAC_NONE, NULL );
// Specify info for the proxy.
server_instance = {&IID_ISecret, NULL, S_OK};
server_machine = {0, L"ServerMachineName", NULL, 0};
// Create a proxy.
CoCreateInstanceEx( CLSID_Secret, NULL, CLSCTX_REMOTE_SERVER,
&server_machine, 1, &server_instance);
pSecret = (ISecret *) server_instance.pItf;
//** The client obtained the server's certificate during the handshake.
//** The server requests a certificate from the client.
// Get the default certificate provider.
CryptAcquireContext( &provider, NULL, NULL, PROV_RSA_SCHANNEL, 0 );
// Open the certificate store.
cert_store = CertOpenSystemStore( provider, L"my" );
// Find the client's certificate.
client_cert =
CertFindCertificateInStore( cert_store,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR,
L"ClientName", // Use the principal name
NULL );
// Find the fullsic principal name of the server.
RpcCertGeneratePrincipalName( server_cert, RPC_C_FULL_CERT_CHAIN,
&server_princ_name );
// Change the client's security:
// Increase the authentication level and attach a certificate.
CoSetProxyBlanket( pSecret, RPC_C_AUTHN_GSS_SCHANNEL,
RPC_C_AUTHZ_NONE,
server_princ_name, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE,
(RPC_AUTH_IDENTITY_HANDLE *) client_cert,
EOAC_NONE );
cleanup:
if (server_princ_name != NULL)
RpcStringFree( &server_princ_name );
if (client_cert != NULL)
CertFreeCertificateContext(client_cert);
if (server_cert != NULL)
CertFreeCertificateContext(server_cert);
if (cert_store != NULL)
CertCloseStore( cert_store, CERT_CLOSE_STORE_CHECK_FLAG );
if (provider != 0 )
CryptReleaseContext( provider, 0 );
if (pSecret != NULL)
pSecret->Release();
CoUninitialize();
}
Tópicos relacionados