Schannel

Le package de sécurité Schannel (Secure Channel), dont l’identificateur de service d’authentification est RPC_C_AUTHN_GSS_SCHANNEL, prend en charge les protocoles basés sur une clé publique suivants : SSL (Secure Sockets Layer) versions 2.0 et 3.0, TLS (Transport Layer Security) 1.0 et PCT (Private Communication Technology) 1.0. TLS 1.0 est une version standardisée et légèrement modifiée de SSL 3.0 qui a été émise par l’Internet Engineering Task Force (IETF) en janvier 1999, dans le document RFC 2246. Étant donné que TLS a été standardisé, les développeurs sont encouragés à utiliser TLS plutôt que SSL. LE PCT est inclus uniquement pour la compatibilité descendante et ne doit pas être utilisé pour les nouveaux développements. Lorsque le package de sécurité Schannel est utilisé, DCOM négocie automatiquement le meilleur protocole, en fonction des fonctionnalités du client et du serveur.

Les rubriques suivantes décrivent brièvement le protocole TLS et son fonctionnement avec DCOM.

Notes

Toutes les informations sur le protocole TLS contenues dans ces sections s’appliquent également aux protocoles SSL et PCT.

 

Quand utiliser TLS

TLS est la seule option de sécurité disponible lorsque les serveurs doivent prouver leur identité à des clients anonymes. Cela est particulièrement important pour les sites web qui souhaitent participer au commerce électronique, car il permet de protéger la transmission d’informations sensibles telles que les numéros de crédit carte. TLS garantit que les clients du commerce électronique peuvent être certains de la personne avec laquelle ils font affaire, car ils reçoivent une preuve de l’identité du serveur. Il donne également au serveur e-commerce l’efficacité de ne pas avoir à se préoccuper de l’authentification de l’identité de chacun de ses clients.

TLS exige que tous les serveurs prouvent leur identité aux clients. En outre, TLS permet aux clients de prouver leur identité aux serveurs. Cette authentification mutuelle peut être utile pour restreindre l’accès de certaines pages web dans un intranet d’entreprise volumineux.

TLS prend en charge les niveaux d’authentification les plus élevés et offre une architecture ouverte qui permet d’augmenter la puissance de chiffrement au fil du temps pour suivre l’innovation technologique. TLS est le meilleur choix pour les environnements où le niveau de sécurité le plus élevé est souhaité pour les données en transit.

Brève vue d’ensemble du fonctionnement de TLS

TLS repose sur une infrastructure à clé publique (PKI), qui utilise des paires de clés publiques/privées pour activer le chiffrement des données et établir l’intégrité des données, et utilise des certificats X.509 pour l’authentification.

De nombreux protocoles de sécurité, tels que le protocole Kerberos v5, dépendent d’une clé unique pour chiffrer et déchiffrer les données. De tels protocoles dépendent donc de l’échange sécurisé de clés de chiffrement ; dans le protocole Kerberos, cela s’effectue via des tickets obtenus à partir du centre de distribution de clés (KDC). Cela nécessite que toute personne utilisant le protocole Kerberos soit inscrite auprès du KDC, ce qui serait une limitation peu pratique pour un serveur web de commerce électronique destiné à attirer des millions de clients du monde entier. TLS s’appuie donc sur une clé PKI, qui utilise deux clés pour le chiffrement des données . « Lorsqu’une clé de la paire chiffre les données, seule l’autre clé de la paire peut les déchiffrer. Le principal avantage de cette conception est que le chiffrement peut être effectué sans nécessiter l’échange sécurisé de clés de chiffrement.

Une clé PKI utilise une technique où l’une des clés est conservée privée et est disponible uniquement pour le principal auquel elle est inscrite, tandis que l’autre clé est rendue publique pour que quiconque puisse y accéder. Si quelqu’un souhaite envoyer un message privé au propriétaire d’une paire de clés, le message peut être chiffré avec la clé publique et seule la clé privée peut être utilisée pour déchiffrer le message.

Les paires de clés sont également utilisées pour vérifier l’intégrité des données envoyées. Pour ce faire, le propriétaire de la paire de clés peut attacher une signature numérique aux données avant de les envoyer. La création d’une signature numérique implique le calcul d’un hachage des données et le chiffrement du hachage avec la clé privée. Toute personne qui utilise la clé publique pour déchiffrer la signature numérique est assurée que la signature numérique doit provenir uniquement de la personne propriétaire de la clé privée. En outre, le destinataire peut calculer un hachage des données à l’aide du même algorithme que l’expéditeur, et si le hachage calculé correspond à celui envoyé dans la signature numérique, le destinataire peut être certain que les données n’ont pas été modifiées une fois qu’elles ont été signées numériquement.

L’un des inconvénients de l’utilisation d’une clé publique pour le chiffrement de données à volume élevé est ses performances relativement lentes. En raison des mathématiques intensives impliquées, le chiffrement et le déchiffrement des données à l’aide d’un chiffrement asymétrique qui dépend d’une paire de clés peuvent être jusqu’à 1 000 fois plus lents que le chiffrement et le déchiffrement à l’aide d’un chiffrement symétrique qui ne dépend que d’une seule clé. TLS utilise donc une clé PKI uniquement pour générer des signatures numériques et pour négocier la clé unique spécifique à la session qui sera utilisée à la fois par le client et le serveur pour le chiffrement et le déchiffrement des données en bloc. TLS prend en charge un large éventail de chiffrements symétriques à clé unique, et des chiffrements supplémentaires peuvent être ajoutés à l’avenir.

Pour plus d’informations sur le protocole d’établissement d’une liaison TLS, consultez Protocole d’établissement d’une liaison TLS.

Pour plus d’informations sur le chiffrement derrière le protocole TLS, consultez Cryptography Essentials.

Certificats X.509

Un problème critique qui doit être géré par une PKI est la capacité à approuver l’authenticité de la clé publique utilisée. Lorsque vous utilisez une clé publique émise à une entreprise avec laquelle vous souhaitez faire affaire, vous voulez être certain que la clé appartient réellement à l’entreprise plutôt qu’à un voleur qui veut découvrir votre numéro de crédit carte.

Pour garantir l’identité d’un principal qui détient une paire de clés, un certificat X.509 est émis par une autorité de certification . Ce certificat contient des informations qui identifient le principal, contiennent la clé publique du principal et sont signés numériquement par l’autorité de certification. Cette signature numérique indique que l’autorité de certification estime que la clé publique contenue dans le certificat appartient vraiment au principal identifié par le certificat.

Et comment faites-vous confiance à l’autorité de certification ? Étant donné que l’autorité de certification elle-même contient un certificat X.509 qui a été signé par une autorité de certification de niveau supérieur. Cette chaîne de signatures de certificat se poursuit jusqu’à ce qu’elle atteigne une autorité de certification racine, qui est une autorité de certification qui signe ses propres certificats. Si vous approuvez l’intégrité de l’autorité de certification racine d’un certificat, vous devez être en mesure d’approuver l’authenticité du certificat lui-même. Par conséquent, le choix des autorités de certification racines auxquelles vous êtes prêt à faire confiance est une obligation importante pour un administrateur système.

Certificats clients

Lorsque les protocoles de couche de transport de sécurité sont apparus pour la première fois, leur objectif principal était de garantir qu’un client se connectait à un serveur authentique et de protéger la confidentialité des données en transit. Toutefois, SSL 3.0 et TLS 1.0 prennent également en charge la transmission du certificat d’un client pendant l’établissement d’une liaison du protocole. Cette fonctionnalité facultative active l’authentification mutuelle du client et du serveur.

La décision d’utiliser ou non un certificat client doit être prise dans le contexte de l’application. Les certificats clients ne sont pas nécessaires si l’exigence principale est l’authentification du serveur. Toutefois, si l’authentification client est essentielle, le certificat d’un client peut être utilisé au lieu de s’appuyer sur l’authentification personnalisée au sein de l’application. L’utilisation de certificats clients est préférable à l’authentification personnalisée, car elle offre aux utilisateurs un scénario d’authentification unique.

Utilisation de TLS dans COM

TLS prend uniquement en charge le niveau d’emprunt d’identité (RPC_C_IMP_LEVEL_IMPERSONATE). Si COM négocie TLS en tant que service d’authentification sur un proxy, COM définit le niveau d’emprunt d’identité pour emprunter l’identité, quel que soit le processus par défaut. Pour que l’emprunt d’identité fonctionne correctement dans TLS, le client doit fournir un certificat X.509 au serveur et ce certificat doit être mappé à un compte d’utilisateur particulier sur le serveur. Pour plus d’informations, consultez le Guide pas à pas pour mapper des certificats à des comptes d’utilisateur.

TLS ne prend pas en charge l’occultation. Si un indicateur de verrouillage et TLS sont spécifiés dans un appel CoInitializeSecurity ou IClientSecurity::SetBlanket , E_INVALIDARG sera retourné.

TLS ne fonctionne pas avec le niveau d’authentification défini sur Aucun. La négociation entre le client et le serveur examine le niveau d’authentification défini par chacun et choisit le paramètre de sécurité le plus élevé pour la connexion.

Les paramètres de sécurité pour TLS peuvent être définis en appelant CoInitializeSecurity et CoSetProxyBlanket. Les sections suivantes décrivent les nuances impliquées dans la réalisation de ces appels.

Comment un serveur définit la couverture de sécurité

Si un serveur souhaite utiliser TLS, il doit spécifier Schannel (RPC_C_AUTHN_GSS_SCHANNEL) comme service d’authentification dans le paramètre asAuthSvc de CoInitializeSecurity. Pour empêcher les clients de se connecter au serveur à l’aide d’un service d’authentification moins sécurisé, le serveur doit spécifier uniquement Schannel comme service d’authentification lorsqu’il appelle CoInitializeSecurity. Le serveur ne peut pas modifier la couverture de sécurité après avoir appelé CoInitializeSecurity.

Pour utiliser TLS, les paramètres suivants doivent être spécifiés lorsqu’un serveur appelle CoInitializeSecurity :

  • pVoid doit être un pointeur vers un objet IAccessControl ou un pointeur vers un SECURITY_DESCRIPTOR. Il ne doit pas être NULL ou un pointeur vers un AppID.
  • cAuthSvc ne peut pas être 0 ou -1. Les serveurs COM ne choisissent jamais Schannel lorsque cAuthSvca la valeur -1.
  • asAuthSvc doit spécifier Schannel comme service d’authentification possible. Pour ce faire, définissez les paramètres de SOLE_AUTHENTICATION_SERVICE suivants pour le membre Schannel du SOLE_AUTHENTICATION_LIST :
    • dwAuthnSvc doit être RPC_C_AUTHN_GSS_SCHANNEL.
    • dwAuthzSvc doit être RPC_C_AUTHZ_NONE. Actuellement, il est ignoré.
    • pPrincipalName doit être un pointeur vers un CERT_CONTEXT, cast en tant que pointeur vers OLECHAR, qui représente le certificat X.509 du serveur.
  • dwAuthnLevel indique le niveau d’authentification minimal qui sera accepté par les clients pour une connexion réussie. Il ne peut pas être RPC_C_AUTHN_LEVEL_NONE.
  • dwCapabilities ne doit pas avoir l’indicateur EOAC_APPID défini. L’indicateur EOAC_ACCESS_CONTROL doit être défini si pVoid pointe vers un objet IAccessControl ; il ne doit pas être défini si pVoid pointe vers un SECURITY_DESCRIPTOR. Pour d’autres indicateurs qui peuvent être définis, consultez CoInitializeSecurity.

Pour plus d’informations sur l’utilisation de CoInitializeSecurity, consultez Définition de la sécurité à l’échelle du processus avec CoInitializeSecurity.

Comment un client définit la couverture de sécurité

Si un client souhaite utiliser TLS, il doit spécifier Schannel (RPC_C_AUTHN_GSS_SCHANNEL) dans sa liste de services d’authentification dans le paramètre pAuthList de CoInitializeSecurity. Si Schannel n’est pas spécifié en tant que service d’authentification possible lorsque CoInitializeSecurity est appelé, un appel ultérieur à CoSetProxyBlanket (ou IClientSecurity::SetBlanket) échouera s’il tente de spécifier Schannel comme service d’authentification.

Les paramètres suivants doivent être spécifiés lorsqu’un client appelle CoInitializeSecurity :

  • dwAuthnLevel spécifie le niveau d’authentification par défaut que le client souhaite utiliser. Il ne peut pas être RPC_C_AUTHN_LEVEL_NONE.
  • dwImpLevel doit être RPC_C_IMP_LEVEL_IMPERSONATE.
  • pAuthList doit avoir les paramètres SOLE_AUTHENTICATION_INFO suivants en tant que membre de la liste :
    • dwAuthnSvc doit être RPC_C_AUTHN_GSS_SCHANNEL.
    • dwAuthzSvc doit être RPC_C_AUTHZ_NONE.
    • pAuthInfo est un pointeur vers un CERT_CONTEXT, qui représente le certificat X.509 du client. Si le client n’a pas de certificat ou ne souhaite pas présenter son certificat au serveur, pAuthInfo doit être NULL et une connexion anonyme est tentée avec le serveur.
  • dwCapabilities est un ensemble d’indicateurs qui indiquent des fonctionnalités client supplémentaires. Pour plus d’informations sur les indicateurs à définir, consultez CoInitializeSecurity .

Pour plus d’informations sur l’utilisation de CoInitializeSecurity, consultez Définition de la sécurité à l’échelle du processus avec CoInitializeSecurity.

Comment un client modifie la couverture de sécurité

Si un client souhaite utiliser TLS mais modifier la couverture de sécurité après avoir appelé CoInitializeSecurity, il doit appeler CoSetProxyBlanket ou IClientSecurity::SetBlanket avec des paramètres similaires à ceux utilisés dans l’appel à CoInitializeSecurity, avec les différences suivantes :

  • pServerPrincName indique le nom principal du serveur, au format msstd ou fullsic. Pour plus d’informations sur ces formats, consultez Noms principaux. Si le client a le certificat X.509 du serveur, il peut trouver le nom principal en appelant RpcCertGeneratePrincipalName.
  • pAuthInfo est un pointeur vers un CERT_CONTEXT, cast en tant que pointeur vers RPC_AUTH_IDENTITY_HANDLE, qui représente le certificat X.509 du client. Si le client n’a pas de certificat ou ne souhaite pas présenter son certificat au serveur, pAuthInfo doit être NULL et une connexion anonyme est tentée avec le serveur.
  • dwCapabilities se compose d’indicateurs qui indiquent des fonctionnalités client supplémentaires. Seuls quatre indicateurs peuvent être utilisés pour modifier les paramètres de couverture de sécurité : EOAC_DEFAULT, EOAC_MUTUAL_AUTH, EOAC_ANY_AUTHORITY (cet indicateur est déconseillé) et EOAC_MAKE_FULLSIC. Pour plus d’informations, consultez CoSetProxyBlanket.

Pour plus d’informations sur l’utilisation de CoSetProxyBlanket, consultez Définition de la sécurité au niveau du proxy d’interface.

Exemple : Le client modifie la couverture de sécurité

L’exemple suivant montre comment un client peut modifier la couverture de sécurité pour prendre en charge une demande du serveur pour que le client fournisse son certificat X.509. Le code de gestion des erreurs est omis par souci de concision.

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();
}

Packages COM et sécurité