Schannel
El paquete de seguridad de Canal seguro (Schannel), cuyo identificador de servicio de autenticación es RPC_C_AUTHN_GSS_SCHANNEL, admite los siguientes protocolos basados en clave pública: SSL (Capa de sockets seguros) versiones 2.0 y 3.0, Seguridad de la capa de transporte (TLS) 1.0 y Tecnología de comunicación privada (PCT) 1.0. TLS 1.0 es una versión estandarizada y ligeramente modificada de SSL 3.0 emitida por el Grupo de tareas de ingeniería de Internet (IETF) en enero de 1999, en el documento RFC 2246. Dado que TLS se ha estandarizado, se recomienda a los desarrolladores usar TLS en lugar de SSL. El PCT se incluye únicamente para la compatibilidad con versiones anteriores y no debe utilizarse para el nuevo desarrollo. Cuando se usa el paquete de seguridad de Schannel, DCOM negocia automáticamente el mejor protocolo, en función de las funcionalidades de cliente y servidor.
En los temas siguientes se describe brevemente el protocolo TLS y cómo funciona con DCOM.
- Cuándo usar TLS
- Breve información general sobre cómo funciona TLS
- Certificados X.509
- Uso de TLS en COM
- Temas relacionados
Nota
Toda la información sobre el protocolo TLS en estas secciones también se aplica a los protocolos SSL y PCT.
TLS es la única opción de seguridad disponible cuando los servidores necesitan demostrar su identidad a clientes anónimos. Esto es especialmente importante para los sitios web que desean participar en el comercio electrónico, ya que ayuda a proteger la transmisión de información confidencial, como números de tarjetas de crédito. TLS garantiza que los clientes de comercio electrónico pueden estar seguros de quiénes están haciendo negocios porque se les da una prueba de la identidad del servidor. También proporciona al servidor de comercio electrónico la eficacia de no tener que preocuparse por la autenticación de la identidad de cada uno de sus clientes.
TLS requiere que todos los servidores demuestren su identidad a los clientes. Además, TLS proporciona la opción de hacer que los clientes demuestren su identidad en los servidores. Esta autenticación mutua puede ser útil para restringir el acceso de determinadas páginas web en una intranet corporativa de gran tamaño.
TLS admite los niveles de autenticación más seguros y ofrece una arquitectura abierta que permite aumentar la intensidad del cifrado con el tiempo para mantenerse al día con la innovación tecnológica. TLS es la mejor opción para los entornos en los que se desea el mayor nivel de seguridad para los datos en tránsito.
TLS se basa en una infraestructura de clave pública (PKI), que usa pares de claves públicas y privadas para habilitar el cifrado de datos y establecer la integridad de los datos, y usa certificados X.509 para la autenticación.
Muchos protocolos de seguridad, como el protocolo Kerberos v5, dependen de una sola clave para cifrar y descifrar datos. Por lo tanto, dichos protocolos dependen del intercambio seguro de claves de cifrado; en el protocolo Kerberos, esto se realiza a través de vales obtenidos del Centro de distribución de claves (KDC). Esto requiere que todos los usuarios que usen el protocolo Kerberos se registren con el KDC, lo que sería una limitación poco práctica para un servidor web de comercio electrónico destinado a atraer a millones de clientes de todo el mundo. Por lo tanto, TLS se basa en una PKI, que usa dos claves para el cifrado de datos: cuando una clave del par cifra los datos, solo la otra clave del par puede descifrarla. La ventaja principal de este diseño es que el cifrado se puede realizar sin requerir el intercambio seguro de claves de cifrado.
Una PKI usa una técnica en la que una de las claves se mantiene privada y solo está disponible para la entidad de seguridad a la que está registrada, mientras que la otra clave se hace pública para que cualquier persona acceda. Si alguien quiere enviar un mensaje privado al propietario de un par de claves, el mensaje se puede cifrar con la clave pública y solo se puede usar la clave privada para descifrar el mensaje.
Los pares clave también se usan para comprobar la integridad de los datos que se envían. Para ello, el propietario del par de claves puede adjuntar una firma digital a los datos antes de enviarlos. La creación de una firma digital implica calcular un hash de los datos y cifrar el hash con la clave privada. Cualquier persona que use la clave pública para descifrar la firma digital está seguro de que la firma digital debe haber venido solo de la persona que posee la clave privada. Además, el destinatario puede calcular un hash de los datos con el mismo algoritmo que el remitente y, si el hash calculado coincide con el enviado en la firma digital, el destinatario puede estar seguro de que los datos no se modificaron después de que se firmara digitalmente.
Una desventaja de usar una PKI para el cifrado de datos de gran volumen es su rendimiento relativamente lento. Debido a las matemáticas intensivas implicadas, el cifrado y el descifrado de datos mediante un cifrado asimétrico que depende de un par de claves puede ser hasta 1000 veces más lento que el cifrado y el descifrado mediante un cifrado simétrico que depende solo de una sola clave. Por lo tanto, TLS usa una PKI solo para generar firmas digitales y para negociar la clave única específica de la sesión que usará tanto el cliente como el servidor para el cifrado y el descifrado de datos masivos. TLS admite una amplia variedad de cifrados simétricos de clave única y se pueden agregar cifrados adicionales en el futuro.
Para obtener más información sobre el protocolo de protocolo de enlace TLS, consulte Protocolo de protocolo de protocolo de enlace TLS.
Para obtener más información sobre la criptografía detrás del protocolo TLS, consulte Cryptography Essentials.
Un problema crítico que debe controlar una PKI es la capacidad de confiar en la autenticidad de la clave pública que se está usando. Cuando se usa una clave pública emitida a una empresa con la que desea hacer negocios, desea estar seguro de que la clave pertenece realmente a la empresa en lugar de a un ladrón que quiere descubrir su número de tarjeta de crédito.
Para garantizar la identidad de una entidad de seguridad que contiene un par de claves, la entidad de seguridad emite un certificado X.509 mediante una entidad de certificación (CA). Este certificado contiene información que identifica la entidad de seguridad, contiene la clave pública de la entidad de seguridad y está firmada digitalmente por la ENTIDAD de certificación. Esta firma digital indica que la ENTIDAD de certificación cree que la clave pública contenida en el certificado pertenece realmente a la entidad de seguridad identificada por el certificado.
¿Y cómo confía en la ENTIDAD de certificación? Dado que la propia ENTIDAD de certificación contiene un certificado X.509 firmado por una entidad de certificación de nivel superior. Esta cadena de firmas de certificado continúa hasta que llega a una entidad de certificación raíz, que es una ENTIDAD de certificación que firma sus propios certificados. Si confía en la integridad de la entidad de certificación raíz de un certificado, debe poder confiar en la autenticidad del propio certificado. Por lo tanto, elegir ca raíz que esté dispuesto a confiar es un deber importante para un administrador del sistema.
Cuando surgió por primera vez los protocolos de capa de transporte de seguridad, su objetivo principal era garantizar que un cliente se conectaba a un servidor auténtico y ayudar a proteger la privacidad de los datos mientras estaba en tránsito. Sin embargo, SSL 3.0 y TLS 1.0 también incluyen compatibilidad con la transmisión del certificado de un cliente durante el protocolo de enlace del protocolo. Esta característica opcional habilita la autenticación mutua del cliente y el servidor.
Decisión de si se debe usar un certificado de cliente en el contexto de la aplicación. Los certificados de cliente no son necesarios si el requisito principal está autenticando el servidor. Sin embargo, si la autenticación de cliente es esencial, se puede usar el certificado de un cliente en lugar de confiar en la autenticación personalizada dentro de la aplicación. El uso de certificados de cliente es preferible sobre la autenticación personalizada, ya que proporciona a los usuarios un escenario de inicio de sesión único.
TLS solo admite el nivel de suplantación (RPC_C_IMP_LEVEL_IMPERSONATE) de suplantación. Si COM negocia TLS como servicio de autenticación en un proxy, COM establecerá el nivel de suplantación para suplantar independientemente del valor predeterminado del proceso. Para que la suplantación funcione correctamente en TLS, el cliente debe proporcionar un certificado X.509 al servidor y el servidor debe tener ese certificado asignado a una cuenta de usuario determinada en el servidor. Para obtener más información, consulte la Guía paso a paso para asignar certificados a cuentas de usuario.
TLS no admite el ocultamiento. Si se especifica una marca de ocultación y TLS en una llamada a CoInitializeSecurity o IClientSecurity::SetBlanket , se devolverá E_INVALIDARG.
TLS no funciona con el nivel de autenticación establecido en Ninguno. El protocolo de enlace entre el cliente y el servidor examina el nivel de autenticación establecido por cada uno y elige la configuración de seguridad más alta para la conexión.
Los parámetros de seguridad para TLS se pueden establecer llamando a CoInitializeSecurity y CoSetProxyBlanket. En las secciones siguientes se describen los matices implicados en la realización de esas llamadas.
Si un servidor quiere usar TLS, debe especificar Schannel (RPC_C_AUTHN_GSS_SCHANNEL) como servicio de autenticación en el parámetro asAuthSvc de CoInitializeSecurity. Para evitar que los clientes se conecten al servidor mediante un servicio de autenticación menos seguro, el servidor solo debe especificar Schannel como servicio de autenticación cuando llama a CoInitializeSecurity. El servidor no puede cambiar la manta de seguridad después de llamar a CoInitializeSecurity.
Para usar TLS, se deben especificar los parámetros siguientes cuando un servidor llama a CoInitializeSecurity:
- pVoid debe ser un puntero a un objeto IAccessControl o un puntero a un SECURITY_DESCRIPTOR. No debe ser NULL ni un puntero a un AppID.
- cAuthSvc no puede ser 0 o -1. Los servidores COM nunca eligen Schannel cuando cAuthSvces -1.
-
asAuthSvc debe especificar Schannel como posible servicio de autenticación. Para ello, establezca los siguientes parámetros de SOLE_AUTHENTICATION_SERVICE para el miembro Schannel del SOLE_AUTHENTICATION_LIST:
- dwAuthnSvc debe ser RPC_C_AUTHN_GSS_SCHANNEL.
- dwAuthzSvc debe ser RPC_C_AUTHZ_NONE. Actualmente, se omite.
- pPrincipalName debe ser un puntero a un CERT_CONTEXT, convertido como puntero a OLECHAR, que representa el certificado X.509 del servidor.
- dwAuthnLevel indica el nivel de autenticación mínimo que se aceptará de los clientes para una conexión correcta. No puede ser RPC_C_AUTHN_LEVEL_NONE.
- dwCapabilities no debe tener establecida la marca EOAC_APPID. La marca EOAC_ACCESS_CONTROL debe establecerse si pVoid apunta a un objeto IAccessControl ; no debe establecerse si pVoid apunta a un SECURITY_DESCRIPTOR. Para ver otras marcas que se pueden establecer, consulte CoInitializeSecurity.
Para obtener más información sobre el uso de CoInitializeSecurity, vea Establecer seguridad en todo el proceso con CoInitializeSecurity.
Si un cliente quiere usar TLS, debe especificar Schannel (RPC_C_AUTHN_GSS_SCHANNEL) en su lista de servicios de autenticación en el parámetro pAuthList de CoInitializeSecurity. Si no se especifica Schannel como un servicio de autenticación posible cuando se llama a CoInitializeSecurity , se producirá un error en una llamada posterior a CoSetProxyBlanket (o IClientSecurity::SetBlanket) si intenta especificar Schannel como servicio de autenticación.
Se deben especificar los parámetros siguientes cuando un cliente llama a CoInitializeSecurity:
- dwAuthnLevel especifica el nivel de autenticación predeterminado que el cliente quiere usar. No puede ser RPC_C_AUTHN_LEVEL_NONE.
- dwImpLevel debe ser RPC_C_IMP_LEVEL_IMPERSONATE.
-
pAuthList debe tener los siguientes parámetros SOLE_AUTHENTICATION_INFO como miembro de la lista:
- dwAuthnSvc debe ser RPC_C_AUTHN_GSS_SCHANNEL.
- dwAuthzSvc debe ser RPC_C_AUTHZ_NONE.
- pAuthInfo es un puntero a un CERT_CONTEXT, convertido como puntero a void, que representa el certificado X.509 del cliente. Si el cliente no tiene un certificado o no desea presentar su certificado al servidor, pAuthInfo debe ser NULL y se intentará una conexión anónima con el servidor.
- dwCapabilities es un conjunto de marcas que indican funcionalidades de cliente adicionales. Consulte CoInitializeSecurity para obtener información sobre qué marcas se deben establecer.
Para obtener más información sobre el uso de CoInitializeSecurity, vea Establecer seguridad en todo el proceso con CoInitializeSecurity.
Si un cliente quiere usar TLS pero cambiar la cobertura de seguridad después de llamar a CoInitializeSecurity, debe llamar a CoSetProxyBlanket o IClientSecurity::SetBlanket con parámetros similares a los usados en la llamada a CoInitializeSecurity, con las siguientes diferencias:
- pServerPrincName indica el nombre principal del servidor, en formato msstd o fullsic. Para obtener información sobre estos formatos, consulte Nombres principales. Si el cliente tiene el certificado X.509 del servidor, puede encontrar el nombre principal llamando a RpcCertGeneratePrincipalName.
- pAuthInfo es un puntero a un CERT_CONTEXT, convertido como puntero a RPC_AUTH_IDENTITY_HANDLE, que representa el certificado X.509 del cliente. Si el cliente no tiene un certificado o no desea presentar su certificado al servidor, pAuthInfo debe ser NULL y se intentará una conexión anónima con el servidor.
- dwCapabilities consta de marcas que indican funcionalidades de cliente adicionales. Solo se pueden usar cuatro marcas para cambiar la configuración general de seguridad: EOAC_DEFAULT, EOAC_MUTUAL_AUTH, EOAC_ANY_AUTHORITY (esta marca está en desuso) y EOAC_MAKE_FULLSIC. Para obtener más información, consulte CoSetProxyBlanket.
Para obtener más información sobre el uso de CoSetProxyBlanket, vea Establecer la seguridad en el nivel de proxy de interfaz.
En el ejemplo siguiente se muestra cómo un cliente puede cambiar la cobertura de seguridad para dar cabida a una solicitud del servidor para que el cliente proporcione su certificado X.509. El código de control de errores se omite para mayor brevedad.
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();
}