Schannel

Säkerhetspaketet Säker kanal (Schannel), vars identifierare för autentiseringstjänsten är RPC_C_AUTHN_GSS_SCHANNEL, stöder följande offentliga nyckelbaserade protokoll: SSL-versionerna (Secure Sockets Layer) version 2.0 och 3.0, TLS (Transport Layer Security) 1.0 och PCT 1.0 (Private Communication Technology). TLS 1.0 är en standardiserad, något modifierad version av SSL 3.0 som utfärdades av IETF (Internet Engineering Task Force) i januari 1999 i dokumentet RFC 2246. Eftersom TLS har standardiserats uppmanas utvecklare att använda TLS i stället för SSL. PCT ingår endast för bakåtkompatibilitet och bör inte användas för ny utveckling. När Schannel-säkerhetspaketet används förhandlar DCOM automatiskt om det bästa protokollet, beroende på klient- och serverfunktionerna.

Följande avsnitt beskriver kortfattat TLS-protokollet och hur det fungerar med DCOM.

Anmärkning

All information om TLS-protokollet i dessa avsnitt gäller även för SSL- och PCT-protokollen.

 

När du ska använda TLS

TLS är det enda tillgängliga säkerhetsalternativet när servrar behöver bevisa sin identitet för anonyma klienter. Detta är särskilt viktigt för webbplatser som vill delta i e-handel eftersom det hjälper till att skydda överföringen av känslig information, till exempel kreditkortsnummer. TLS försäkrar att e-handelskunderna kan vara säkra på vilka de gör affärer med eftersom de får bevis på serverns identitet. Det ger också e-handelsservern effektiviteten att inte behöva bry sig om att autentisera identiteten för var och en av sina kunder.

TLS kräver att alla servrar bevisar sin identitet för klienter. Dessutom ger TLS möjlighet att låta klienter bevisa sin identitet för servrar. Den här ömsesidiga autentiseringen kan vara användbar för att begränsa åtkomsten till vissa webbsidor i ett stort företags intranät.

TLS har stöd för de starkaste autentiseringsnivåerna och erbjuder en öppen arkitektur som gör att krypteringsstyrkan kan öka med tiden för att hänga med i den tekniska innovationen. TLS är det bästa valet för miljöer där den högsta säkerhetsnivån önskas för data under överföring.

Kort översikt över hur TLS fungerar

TLS bygger på en offentlig nyckelinfrastruktur (PKI), som använder offentliga/privata nyckelpar för att aktivera datakryptering och upprätta dataintegritet, och använder X.509-certifikat för autentisering.

Många säkerhetsprotokoll, till exempel Kerberos v5-protokollet, är beroende av en enda nyckel för att både kryptera och dekryptera data. Sådana protokoll är därför beroende av ett säkert utbyte av krypteringsnycklar. I Kerberos-protokollet görs detta via biljetter som hämtats från Key Distribution Center (KDC). Detta kräver att alla som använder Kerberos-protokollet registreras med KDC, vilket skulle vara en opraktisk begränsning för en e-handelswebbserver som är avsedd att locka miljontals kunder från hela världen. TLS förlitar sig därför på en PKI, som använder två nycklar för datakryptering – när en nyckel i paret krypterar data kan endast den andra nyckeln i paret dekryptera dem. Huvudfördelarna med den här designen är att kryptering kan utföras utan att kräva ett säkert utbyte av krypteringsnycklar.

En PKI använder en teknik där en av nycklarna hålls privat och endast är tillgänglig för det huvudnamn som den är registrerad för, medan den andra nyckeln görs offentlig för vem som helst att komma åt. Om någon vill skicka ett privat meddelande till ägaren av ett nyckelpar kan meddelandet krypteras med den offentliga nyckeln och endast den privata nyckeln kan användas för att dekryptera meddelandet.

Nyckelpar används också för att verifiera integriteten för de data som skickas. För att göra detta kan nyckelparets ägare koppla en digital signatur till data innan de skickas. Att skapa en digital signatur innebär att beräkna en hash av data och kryptera hashen med den privata nyckeln. Den som använder den offentliga nyckeln för att dekryptera den digitala signaturen är säker på att den digitala signaturen bara måste ha kommit från den person som äger den privata nyckeln. Dessutom kan mottagaren beräkna en hash av data med samma algoritm som avsändaren, och om den beräknade hashen matchar den som skickas i den digitala signaturen kan mottagaren vara säker på att data inte har ändrats efter att de har signerats digitalt.

En nackdel med att använda en PKI för datakryptering med hög volym är dess relativt långsamma prestanda. På grund av den intensiva matematiken kan kryptering och dekryptering av data med hjälp av ett asymmetriskt chiffer som är beroende av ett nyckelpar vara upp till 1 000 gånger långsammare än kryptering och dekryptering med hjälp av ett symmetriskt chiffer som bara är beroende av en enda nyckel. TLS använder därför endast en PKI för att generera digitala signaturer och för att förhandla om den sessionsspecifika enskild nyckel som ska användas av både klienten och servern för masskryptering och dekryptering. TLS stöder en mängd olika symmetriska chiffer med en nyckel, och ytterligare chiffer kan läggas till i framtiden.

Mer information om TLS-handskakningsprotokollet finns i TLS Handshake Protocol.

Mer information om kryptografi bakom TLS-protokollet finns i Kryptografi Essentials.

X.509-certifikat

Ett kritiskt problem som måste hanteras av en PKI är möjligheten att lita på äktheten hos den offentliga nyckel som används. När du använder en offentlig nyckel som utfärdats till ett företag som du vill göra affärer med vill du vara säker på att nyckeln faktiskt tillhör företaget snarare än en tjuv som vill upptäcka ditt kreditkortsnummer.

För att garantera identiteten för ett huvudnamn som har ett nyckelpar utfärdas huvudkontot ett X.509-certifikat av en certifikatutfärdare (CA). Det här certifikatet innehåller information som identifierar huvudnamnet, innehåller huvudnamnets offentliga nyckel och är digitalt signerad av certifikatutfärdare. Den här digitala signaturen anger att certifikatutfärdare anser att den offentliga nyckeln i certifikatet verkligen tillhör det huvudnamn som identifieras av certifikatet.

Och hur litar du på ca:en? Eftersom ca:en själv har ett X.509-certifikat som har signerats av en certifikatutfärdare på högre nivå. Den här kedjan med certifikatsignaturer fortsätter tills den når en rotcertifikatutfärdare, som är en certifikatutfärdare som signerar sina egna certifikat. Om du litar på integriteten hos rotcertifikatutfärdare för ett certifikat bör du kunna lita på själva certifikatets äkthet. Därför är det viktigt för en systemadministratör att välja rotcertifikatutfärdare som du är villig att lita på.

Klientcertifikat

När säkerhetsprotokoll på transportnivå först uppstod var deras främsta syfte att garantera att en klient anslöt till en autentisk server och skydda datasekretessen under överföringen. SSL 3.0 och TLS 1.0 innehåller dock även stöd för överföring av en klients certifikat under protokollets handskakning. Den här valfria funktionen möjliggör ömsesidig autentisering av klienten och servern.

Beslutet om att använda ett klientcertifikat ska fattas i samband med programmet. Klientcertifikat är onödiga om det primära kravet är att autentisera servern. Men om klientautentisering är viktigt kan klientens certifikat användas i stället för att förlita sig på anpassad autentisering i programmet. Att använda klientcertifikat är att föredra framför anpassad autentisering eftersom det ger användarna ett scenario med enkel inloggning.

Använda TLS i COM

TLS stöder endast personifieringsnivån (RPC_C_IMP_LEVEL_IMPERSONATE). Om COM förhandlar om TLS som autentiseringstjänst på en proxy anger COM personifieringsnivån så att den personifierar oavsett processstandard. För att personifieringen ska fungera korrekt i TLS måste klienten tillhandahålla ett X.509-certifikat till servern och servern måste ha certifikatet mappat till ett visst användarkonto på servern. Mer information finns i steg-för-steg-guiden för att mappa certifikat till användarkonton.

TLS stöder inte kamouflage. Om en kamouflageflagga och TLS anges i ett CoInitializeSecurity - eller IClientSecurity::SetBlanket-anrop returneras E_INVALIDARG.

TLS fungerar inte med autentiseringsnivån inställd på Ingen. Handskakningen mellan klienten och servern undersöker den autentiseringsnivå som angetts av var och en och väljer den högre säkerhetsinställningen för anslutningen.

Säkerhetsparametrarna för TLS kan anges genom att anropa CoInitializeSecurity och CoSetProxyBlanket. I följande avsnitt beskrivs de nyanser som ingår i att göra dessa anrop.

Så här ställer en server in säkerhetsfilten

Om en server vill använda TLS måste den ange Schannel (RPC_C_AUTHN_GSS_SCHANNEL) som en autentiseringstjänst i parametern asAuthSvc för CoInitializeSecurity. För att förhindra att klienter ansluter till servern med hjälp av en mindre säker autentiseringstjänst bör servern endast ange Schannel som en autentiseringstjänst när den anropar CoInitializeSecurity. Servern kan inte ändra säkerhetsfilten efter att den har anropat CoInitializeSecurity.

Om du vill använda TLS bör följande parametrar anges när en server anropar CoInitializeSecurity:

  • pVoid ska antingen vara en pekare till ett IAccessControl-objekt eller en pekare till en SECURITY_DESCRIPTOR. Det får inte vara NULL eller en pekare till ett AppID.
  • cAuthSvc får inte vara 0 eller -1. COM-servrar väljer aldrig Schannel när cAuthSvcär -1.
  • asAuthSvc måste ange Schannel som en möjlig autentiseringstjänst. Detta görs genom att ange följande SOLE_AUTHENTICATION_SERVICE parametrar för Schannel-medlemmen i SOLE_AUTHENTICATION_LIST:
    • dwAuthnSvc måste vara RPC_C_AUTHN_GSS_SCHANNEL.
    • dwAuthzSvc ska vara RPC_C_AUTHZ_NONE. För närvarande ignoreras den.
    • pPrincipalName måste vara en pekare till en CERT_CONTEXT, som en pekare till OLECHAR, som representerar serverns X.509-certifikat.
  • dwAuthnLevel anger den lägsta autentiseringsnivå som kommer att accepteras från klienter för en lyckad anslutning. Det kan inte vara RPC_C_AUTHN_LEVEL_NONE.
  • dwCapabilities bör inte ha flaggan EOAC_APPID inställd. Flaggan EOAC_ACCESS_CONTROL ska anges om pVoid pekar på ett IAccessControl-objekt . det bör inte anges om pVoid pekar på en SECURITY_DESCRIPTOR. Andra flaggor som kan anges finns i CoInitializeSecurity.

Mer information om hur du använder CoInitializeSecurity finns i Ange processomfattande säkerhet med CoInitializeSecurity.

Så här ställer en klient in säkerhetsfilten

Om en klient vill använda TLS måste den ange Schannel (RPC_C_AUTHN_GSS_SCHANNEL) i sin lista över autentiseringstjänster i parametern pAuthList för CoInitializeSecurity. Om Schannel inte anges som en möjlig autentiseringstjänst när CoInitializeSecurity anropas misslyckas ett senare anrop till CoSetProxyBlanket (eller IClientSecurity::SetBlanket) om det försöker ange Schannel som autentiseringstjänst.

Följande parametrar bör anges när en klient anropar CoInitializeSecurity:

  • dwAuthnLevel anger standardautentiseringsnivån som klienten vill använda. Det kan inte vara RPC_C_AUTHN_LEVEL_NONE.
  • dwImpLevel måste vara RPC_C_IMP_LEVEL_IMPERSONATE.
  • pAuthList måste ha följande SOLE_AUTHENTICATION_INFO parametrar som medlem i listan:
    • dwAuthnSvc måste vara RPC_C_AUTHN_GSS_SCHANNEL.
    • dwAuthzSvc måste vara RPC_C_AUTHZ_NONE.
    • pAuthInfo är en pekare till en CERT_CONTEXT, som skickas som en pekare till void, som representerar klientens X.509-certifikat. Om klienten inte har något certifikat eller inte vill visa upp certifikatet för servern måste pAuthInfo vara NULL och en anonym anslutning görs med servern.
  • dwCapabilities är en uppsättning flaggor som anger ytterligare klientfunktioner. Mer information om vilka flaggor som ska anges finns i CoInitializeSecurity .

Mer information om hur du använder CoInitializeSecurity finns i Ange processomfattande säkerhet med CoInitializeSecurity.

Så här ändrar en klient säkerhetsfilten

Om en klient vill använda TLS men ändrar säkerhetsfilten efter att ha anropat CoInitializeSecurity måste den anropa antingen CoSetProxyBlanket eller IClientSecurity::SetBlanket med parametrar som liknar de som används i anropet till CoInitializeSecurity, med följande skillnader:

  • pServerPrincName anger huvudnamnet för servern, antingen i msstd- eller fullsic-format. Information om dessa format finns i Huvudnamn. Om klienten har serverns X.509-certifikat kan den hitta huvudnamnet genom att anropa RpcCertGeneratePrincipalName.
  • pAuthInfo är en pekare till en CERT_CONTEXT, som en pekare till RPC_AUTH_IDENTITY_HANDLE, som representerar klientens X.509-certifikat. Om klienten inte har något certifikat eller inte vill visa upp certifikatet för servern måste pAuthInfo vara NULL och en anonym anslutning görs med servern.
  • dwCapabilities består av flaggor som anger ytterligare klientfunktioner. Endast fyra flaggor kan användas för att ändra inställningarna för säkerhetsavbildningar: EOAC_DEFAULT, EOAC_MUTUAL_AUTH, EOAC_ANY_AUTHORITY (den här flaggan är inaktuell) och EOAC_MAKE_FULLSIC. Mer information finns i CoSetProxyBlanket.

Mer information om hur du använder CoSetProxyBlanket finnsi Ange säkerhet på gränssnittsproxynivå.

Exempel: Klienten ändrar säkerhetsfilten

I följande exempel visas hur en klient kan ändra säkerhetstäcket för att hantera en begäran från servern om att klienten ska tillhandahålla sitt X.509-certifikat. Felhanteringskod utelämnas för korthet.

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

COM- och säkerhetspaket