Nasıl Yapılır: İmzalama ve Şifreleme için Ayrı X.509 Sertifikaları Kullanma
Bu konuda, Windows Communication Foundation'ın (WCF) hem istemcide hem de hizmette ileti imzalama ve şifreleme için farklı sertifikalar kullanacak şekilde nasıl yapılandırılır gösterilmektedir.
İmzalama ve şifreleme için ayrı sertifikaların kullanılmasını etkinleştirmek için, WCF birden çok istemci veya hizmet sertifikası ayarlamak için bir API sağlamadığından özel bir istemci veya hizmet kimlik bilgileri (veya her ikisi) oluşturulmalıdır. Ayrıca, birden çok sertifikanın bilgilerinden yararlanmak ve belirtilen anahtar kullanımı ve ileti yönü için uygun bir güvenlik belirteci sağlayıcısı oluşturmak için bir güvenlik belirteci yöneticisi sağlanmalıdır.
Aşağıdaki diyagramda kullanılan ana sınıflar, devraldıkları sınıflar (yukarı doğru bir okla gösterilir) ve belirli yöntem ve özelliklerin dönüş türleri gösterilir.
MyClientCredentials
, uygulamasının özel bir uygulamasıdır ClientCredentials.Diyagramda gösterilen özellikleri, öğesinin X509Certificate2tüm örneklerini döndürür.
Yöntemi CreateSecurityTokenManager bir örneğini
MyClientCredentialsSecurityTokenManager
döndürür.
MyClientCredentialsSecurityTokenManager
, uygulamasının özel bir uygulamasıdır ClientCredentialsSecurityTokenManager.- Yöntemi CreateSecurityTokenProvider bir örneğini X509SecurityTokenProviderdöndürür.
Özel kimlik bilgileri hakkında daha fazla bilgi için bkz . İzlenecek Yol: Özel İstemci ve Hizmet Kimlik Bilgileri Oluşturma.
Ayrıca, özel bir kimlik doğrulayıcı oluşturmanız ve bunu özel bağlamadaki bir güvenlik bağlaması öğesine bağlamanız gerekir. Varsayılan kimlik bilgileri yerine özel kimlik bilgilerini de kullanmanız gerekir.
Aşağıdaki diyagramda, özel bağlamada yer alan sınıflar ve özel kimlik doğrulayıcının nasıl bağlı olduğu gösterilmektedir. Dahil olan ve tümü öğesinden BindingElementdevralan birkaç bağlama öğesi vardır. AsymmetricSecurityBindingElement, özelleştirilen bir örneğini IdentityVerifierdöndüren MyIdentityVerifier
özelliğine sahiptirLocalClientSecuritySettings.
Özel kimlik doğrulayıcı oluşturma hakkında daha fazla bilgi için bkz. Nasıl yapılır: Nasıl yapılır: Özel İstemci Kimlik Doğrulayıcısı Oluşturma.
İmzalama ve şifreleme için ayrı sertifikalar kullanmak için
sınıfından ClientCredentials devralan yeni bir istemci kimlik bilgileri sınıfı tanımlayın. Birden çok sertifika belirtimine izin vermek için dört yeni özellik uygulayın:
ClientSigningCertificate
,ClientEncryptingCertificate
,ServiceSigningCertificate
veServiceEncryptingCertificate
. Ayrıca, sonraki adımda tanımlanan özelleştirilmiş ClientCredentialsSecurityTokenManager sınıfın bir örneğini döndürmek için yöntemini geçersiz kılınCreateSecurityTokenManager.public class MyClientCredentials : ClientCredentials { X509Certificate2 clientSigningCert; X509Certificate2 clientEncryptingCert; X509Certificate2 serviceSigningCert; X509Certificate2 serviceEncryptingCert; public MyClientCredentials() { } protected MyClientCredentials(MyClientCredentials other) : base(other) { this.clientEncryptingCert = other.clientEncryptingCert; this.clientSigningCert = other.clientSigningCert; this.serviceEncryptingCert = other.serviceEncryptingCert; this.serviceSigningCert = other.serviceSigningCert; } public X509Certificate2 ClientSigningCertificate { get { return this.clientSigningCert; } set { this.clientSigningCert = value; } } public X509Certificate2 ClientEncryptingCertificate { get { return this.clientEncryptingCert; } set { this.clientEncryptingCert = value; } } public X509Certificate2 ServiceSigningCertificate { get { return this.serviceSigningCert; } set { this.serviceSigningCert = value; } } public X509Certificate2 ServiceEncryptingCertificate { get { return this.serviceEncryptingCert; } set { this.serviceEncryptingCert = value; } } public override SecurityTokenManager CreateSecurityTokenManager() { return new MyClientCredentialsSecurityTokenManager(this); } protected override ClientCredentials CloneCore() { return new MyClientCredentials(this); } }
Public Class MyClientCredentials Inherits ClientCredentials Private clientSigningCert As X509Certificate2 Private clientEncryptingCert As X509Certificate2 Private serviceSigningCert As X509Certificate2 Private serviceEncryptingCert As X509Certificate2 Public Sub New() End Sub Protected Sub New(ByVal other As MyClientCredentials) MyBase.New(other) Me.clientEncryptingCert = other.clientEncryptingCert Me.clientSigningCert = other.clientSigningCert Me.serviceEncryptingCert = other.serviceEncryptingCert Me.serviceSigningCert = other.serviceSigningCert End Sub Public Property ClientSigningCertificate() As X509Certificate2 Get Return Me.clientSigningCert End Get Set(ByVal value As X509Certificate2) Me.clientSigningCert = value End Set End Property Public Property ClientEncryptingCertificate() As X509Certificate2 Get Return Me.clientEncryptingCert End Get Set(ByVal value As X509Certificate2) Me.clientEncryptingCert = value End Set End Property Public Property ServiceSigningCertificate() As X509Certificate2 Get Return Me.serviceSigningCert End Get Set(ByVal value As X509Certificate2) Me.serviceSigningCert = value End Set End Property Public Property ServiceEncryptingCertificate() As X509Certificate2 Get Return Me.serviceEncryptingCert End Get Set(ByVal value As X509Certificate2) Me.serviceEncryptingCert = value End Set End Property Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager Return New MyClientCredentialsSecurityTokenManager(Me) End Function Protected Overrides Function CloneCore() As ClientCredentials Return New MyClientCredentials(Me) End Function End Class
sınıfından ClientCredentialsSecurityTokenManager devralan yeni bir istemci güvenlik belirteci yöneticisi tanımlayın. CreateSecurityTokenProvider Uygun bir güvenlik belirteci sağlayıcısı oluşturmak için yöntemini geçersiz kılın.
requirement
parametresi (aSecurityTokenRequirement) ileti yönünü ve anahtar kullanımını sağlar.internal class MyClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager { MyClientCredentials credentials; public MyClientCredentialsSecurityTokenManager( MyClientCredentials credentials): base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider( SecurityTokenRequirement requirement) { SecurityTokenProvider result = null; if (requirement.TokenType == SecurityTokenTypes.X509Certificate) { MessageDirection direction = requirement.GetProperty <MessageDirection>(ServiceModelSecurityTokenRequirement. MessageDirectionProperty); if (direction == MessageDirection.Output) { if (requirement.KeyUsage == SecurityKeyUsage.Signature) { result = new X509SecurityTokenProvider( this.credentials.ClientSigningCertificate); } else { result = new X509SecurityTokenProvider(this.credentials. ServiceEncryptingCertificate); } } else { if (requirement.KeyUsage == SecurityKeyUsage.Signature) { result = new X509SecurityTokenProvider(this. credentials.ServiceSigningCertificate); } else { result = new X509SecurityTokenProvider(credentials. ClientEncryptingCertificate); } } } else { result = base.CreateSecurityTokenProvider(requirement); } return result; } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } }
Friend Class MyClientCredentialsSecurityTokenManager Inherits ClientCredentialsSecurityTokenManager Private credentials As MyClientCredentials Public Sub New(ByVal credentials As MyClientCredentials) MyBase.New(credentials) Me.credentials = credentials End Sub Public Overrides Function CreateSecurityTokenProvider(ByVal requirement As SecurityTokenRequirement) As SecurityTokenProvider Dim result As SecurityTokenProvider = Nothing If requirement.TokenType = SecurityTokenTypes.X509Certificate Then Dim direction = requirement.GetProperty(Of MessageDirection)(ServiceModelSecurityTokenRequirement.MessageDirectionProperty) If direction = MessageDirection.Output Then If requirement.KeyUsage = SecurityKeyUsage.Signature Then result = New X509SecurityTokenProvider(Me.credentials.ClientSigningCertificate) Else result = New X509SecurityTokenProvider(Me.credentials.ServiceEncryptingCertificate) End If Else If requirement.KeyUsage = SecurityKeyUsage.Signature Then result = New X509SecurityTokenProvider(Me.credentials.ServiceSigningCertificate) Else result = New X509SecurityTokenProvider(credentials.ClientEncryptingCertificate) End If End If Else result = MyBase.CreateSecurityTokenProvider(requirement) End If Return result End Function Public Overrides Function CreateSecurityTokenAuthenticator(ByVal tokenRequirement As SecurityTokenRequirement, _ <System.Runtime.InteropServices.Out()> ByRef outOfBandTokenResolver As SecurityTokenResolver) As SecurityTokenAuthenticator Return MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, _ outOfBandTokenResolver) End Function End Class
sınıfından ServiceCredentials devralan yeni bir hizmet kimlik bilgileri sınıfı tanımlayın. Birden çok sertifika belirtimine izin vermek için dört yeni özellik uygulayın:
ClientSigningCertificate
,ClientEncryptingCertificate
,ServiceSigningCertificate
veServiceEncryptingCertificate
. Ayrıca, sonraki adımda tanımlanan özelleştirilmiş ServiceCredentialsSecurityTokenManager sınıfın bir örneğini döndürmek için yöntemini geçersiz kılınCreateSecurityTokenManager.public class MyServiceCredentials : ServiceCredentials { X509Certificate2 clientSigningCert; X509Certificate2 clientEncryptingCert; X509Certificate2 serviceSigningCert; X509Certificate2 serviceEncryptingCert; public MyServiceCredentials() { } protected MyServiceCredentials(MyServiceCredentials other) : base(other) { this.clientEncryptingCert = other.clientEncryptingCert; this.clientSigningCert = other.clientSigningCert; this.serviceEncryptingCert = other.serviceEncryptingCert; this.serviceSigningCert = other.serviceSigningCert; } public X509Certificate2 ClientSigningCertificate { get { return this.clientSigningCert; } set { this.clientSigningCert = value; } } public X509Certificate2 ClientEncryptingCertificate { get { return this.clientEncryptingCert; } set { this.clientEncryptingCert = value; } } public X509Certificate2 ServiceSigningCertificate { get { return this.serviceSigningCert; } set { this.serviceSigningCert = value; } } public X509Certificate2 ServiceEncryptingCertificate { get { return this.serviceEncryptingCert; } set { this.serviceEncryptingCert = value; } } public override SecurityTokenManager CreateSecurityTokenManager() { return new MyServiceCredentialsSecurityTokenManager(this); } protected override ServiceCredentials CloneCore() { return new MyServiceCredentials(this); } }
Public Class MyServiceCredentials Inherits ServiceCredentials Private clientSigningCert As X509Certificate2 Private clientEncryptingCert As X509Certificate2 Private serviceSigningCert As X509Certificate2 Private serviceEncryptingCert As X509Certificate2 Public Sub New() End Sub Protected Sub New(ByVal other As MyServiceCredentials) MyBase.New(other) Me.clientEncryptingCert = other.clientEncryptingCert Me.clientSigningCert = other.clientSigningCert Me.serviceEncryptingCert = other.serviceEncryptingCert Me.serviceSigningCert = other.serviceSigningCert End Sub Public Property ClientSigningCertificate() As X509Certificate2 Get Return Me.clientSigningCert End Get Set(ByVal value As X509Certificate2) Me.clientSigningCert = value End Set End Property Public Property ClientEncryptingCertificate() As X509Certificate2 Get Return Me.clientEncryptingCert End Get Set(ByVal value As X509Certificate2) Me.clientEncryptingCert = value End Set End Property Public Property ServiceSigningCertificate() As X509Certificate2 Get Return Me.serviceSigningCert End Get Set(ByVal value As X509Certificate2) Me.serviceSigningCert = value End Set End Property Public Property ServiceEncryptingCertificate() As X509Certificate2 Get Return Me.serviceEncryptingCert End Get Set(ByVal value As X509Certificate2) Me.serviceEncryptingCert = value End Set End Property Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager Return New MyServiceCredentialsSecurityTokenManager(Me) End Function Protected Overrides Function CloneCore() As ServiceCredentials Return New MyServiceCredentials(Me) End Function End Class
sınıfından ServiceCredentialsSecurityTokenManager devralan yeni bir hizmet güvenlik belirteci yöneticisi tanımlayın. CreateSecurityTokenProvider Geçirilen ileti yönü ve anahtar kullanımı göz önüne alındığında uygun bir güvenlik belirteci sağlayıcısı oluşturmak için yöntemini geçersiz kılın.
internal class MyServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager { MyServiceCredentials credentials; public MyServiceCredentialsSecurityTokenManager( MyServiceCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider( SecurityTokenRequirement requirement) { SecurityTokenProvider result = null; if (requirement.TokenType == SecurityTokenTypes.X509Certificate) { MessageDirection direction = requirement. GetProperty<MessageDirection>( ServiceModelSecurityTokenRequirement. MessageDirectionProperty); if (direction == MessageDirection.Input) { if (requirement.KeyUsage == SecurityKeyUsage.Exchange) { result = new X509SecurityTokenProvider( credentials.ServiceEncryptingCertificate); } else { result = new X509SecurityTokenProvider( credentials.ClientSigningCertificate); } } else { if (requirement.KeyUsage == SecurityKeyUsage.Signature) { result = new X509SecurityTokenProvider( credentials.ServiceSigningCertificate); } else { result = new X509SecurityTokenProvider( credentials.ClientEncryptingCertificate); } } } else { result = base.CreateSecurityTokenProvider(requirement); } return result; } }
Friend Class MyServiceCredentialsSecurityTokenManager Inherits ServiceCredentialsSecurityTokenManager Private credentials As MyServiceCredentials Public Sub New(ByVal credentials As MyServiceCredentials) MyBase.New(credentials) Me.credentials = credentials End Sub Public Overrides Function CreateSecurityTokenProvider(ByVal requirement As SecurityTokenRequirement) As SecurityTokenProvider Dim result As SecurityTokenProvider = Nothing If requirement.TokenType = SecurityTokenTypes.X509Certificate Then Dim direction = requirement.GetProperty(Of MessageDirection)(ServiceModelSecurityTokenRequirement.MessageDirectionProperty) If direction = MessageDirection.Input Then If requirement.KeyUsage = SecurityKeyUsage.Exchange Then result = New X509SecurityTokenProvider(credentials.ServiceEncryptingCertificate) Else result = New X509SecurityTokenProvider(credentials.ClientSigningCertificate) End If Else If requirement.KeyUsage = SecurityKeyUsage.Signature Then result = New X509SecurityTokenProvider(credentials.ServiceSigningCertificate) Else result = New X509SecurityTokenProvider(credentials.ClientEncryptingCertificate) End If End If Else result = MyBase.CreateSecurityTokenProvider(requirement) End If Return result End Function End Class
İstemcide birden çok sertifika kullanmak için
Özel bir bağlama oluşturun. Farklı güvenlik belirteci sağlayıcılarının istekler ve yanıtlar için mevcut olmasını sağlamak için güvenlik bağlama öğesinin çift yönlü modda çalışması gerekir. Bunu yapmak için çift yönlü özellikli bir taşıma kullanmak veya aşağıdaki kodda gösterildiği gibi kullanmaktır CompositeDuplexBindingElement . Sonraki adımda tanımlanan özelleştirilmiş IdentityVerifier öğesini güvenlik bağlama öğesine bağlayın. Varsayılan istemci kimlik bilgilerini daha önce oluşturulan özelleştirilmiş istemci kimlik bilgileriyle değiştirin.
EndpointAddress serviceEndpoint = new EndpointAddress(new Uri("http://localhost:6060/service")); CustomBinding binding = new CustomBinding(); AsymmetricSecurityBindingElement securityBE = SecurityBindingElement.CreateMutualCertificateDuplexBindingElement( MessageSecurityVersion. WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10); // Add a custom IdentityVerifier because the service uses two certificates // (one for signing and one for encryption) and an endpoint identity that // contains a single identity claim. securityBE.LocalClientSettings.IdentityVerifier = new MyIdentityVerifier(); binding.Elements.Add(securityBE); CompositeDuplexBindingElement compositeDuplex = new CompositeDuplexBindingElement(); compositeDuplex.ClientBaseAddress = new Uri("http://localhost:6061/client"); binding.Elements.Add(compositeDuplex); binding.Elements.Add(new OneWayBindingElement()); binding.Elements.Add(new HttpTransportBindingElement()); using (ChannelFactory<IMyServiceChannel> factory = new ChannelFactory<IMyServiceChannel>(binding, serviceEndpoint)) { MyClientCredentials credentials = new MyClientCredentials(); SetupCertificates(credentials); factory.Endpoint.Behaviors.Remove(typeof(ClientCredentials)); factory.Endpoint.Behaviors.Add(credentials); IMyServiceChannel channel = factory.CreateChannel(); Console.WriteLine(channel.Hello("world")); channel.Close(); }
Dim serviceEndpoint As New EndpointAddress(New Uri("http://localhost:6060/service")) Dim binding As New CustomBinding() Dim securityBE = SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10) ' Add a custom IdentityVerifier because the service uses two certificates ' (one for signing and one for encryption) and an endpoint identity that ' contains a single identity claim. securityBE.LocalClientSettings.IdentityVerifier = New MyIdentityVerifier() binding.Elements.Add(securityBE) Dim compositeDuplex As New CompositeDuplexBindingElement() compositeDuplex.ClientBaseAddress = New Uri("http://localhost:6061/client") With binding.Elements .Add(compositeDuplex) .Add(New OneWayBindingElement()) .Add(New HttpTransportBindingElement()) End With Using factory As New ChannelFactory(Of IMyServiceChannel)(binding, serviceEndpoint) Dim credentials As New MyClientCredentials() SetupCertificates(credentials) With factory.Endpoint.Behaviors .Remove(GetType(ClientCredentials)) .Add(credentials) End With Dim channel = factory.CreateChannel() Console.WriteLine(channel.Hello("world")) channel.Close() End Using
Özel IdentityVerifierbir tanımlayın. İsteği şifrelemek ve yanıtı imzalamak için farklı sertifikalar kullanıldığından hizmetin birden çok kimliği vardır.
Not
Aşağıdaki örnekte, sağlanan özel kimlik doğrulayıcı gösterim amacıyla herhangi bir uç nokta kimliği denetimi gerçekleştirmez. Bu, üretim kodu için önerilmez.
class MyIdentityVerifier : IdentityVerifier { IdentityVerifier defaultVerifier; public MyIdentityVerifier() { this.defaultVerifier = IdentityVerifier.CreateDefault(); } public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext) { // The following implementation is for demonstration only, and // does not perform any checks regarding EndpointIdentity. // Do not use this for production code. return true; } public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity) { return this.defaultVerifier.TryGetIdentity(reference, out identity); } }
Friend Class MyIdentityVerifier Inherits IdentityVerifier Private defaultVerifier As IdentityVerifier Public Sub New() Me.defaultVerifier = IdentityVerifier.CreateDefault() End Sub Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, ByVal authContext As AuthorizationContext) As Boolean ' The following implementation is for demonstration only, and ' does not perform any checks regarding EndpointIdentity. ' Do not use this for production code. Return True End Function Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, <System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean Return Me.defaultVerifier.TryGetIdentity(reference, identity) End Function End Class
Hizmette birden çok sertifika kullanmak için
Özel bir bağlama oluşturun. Farklı güvenlik belirteci sağlayıcılarının istekler ve yanıtlar için mevcut olmasına izin vermek için güvenlik bağlama öğesinin çift yönlü modda çalışması gerekir. İstemcide olduğu gibi, çift yönlü özellikli bir aktarım kullanın veya aşağıdaki kodda gösterildiği gibi kullanın CompositeDuplexBindingElement . Varsayılan hizmet kimlik bilgilerini daha önce oluşturulan özelleştirilmiş hizmet kimlik bilgileriyle değiştirin.
Uri serviceEndpoint = new Uri("http://localhost:6060/service"); using (ServiceHost host = new ServiceHost(typeof(Service), serviceEndpoint)) { CustomBinding binding = new CustomBinding(); binding.Elements.Add(SecurityBindingElement. CreateMutualCertificateDuplexBindingElement( MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10)); binding.Elements.Add(new CompositeDuplexBindingElement()); binding.Elements.Add(new OneWayBindingElement()); binding.Elements.Add(new HttpTransportBindingElement()); MyServiceCredentials credentials = new MyServiceCredentials(); SetupCertificates(credentials); host.Description.Behaviors.Remove(typeof(ServiceCredentials)); host.Description.Behaviors.Add(credentials); ServiceEndpoint endpoint = host.AddServiceEndpoint( typeof(IMyService), binding, ""); host.Open(); Console.WriteLine("Service started, press ENTER to stop..."); Console.ReadLine(); }
Dim serviceEndpoint As New Uri("http://localhost:6060/service") Using host As New ServiceHost(GetType(Service), serviceEndpoint) Dim binding As New CustomBinding() With binding.Elements .Add(SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10)) .Add(New CompositeDuplexBindingElement()) .Add(New OneWayBindingElement()) .Add(New HttpTransportBindingElement()) End With Dim credentials As New MyServiceCredentials() SetupCertificates(credentials) With host.Description.Behaviors .Remove(GetType(ServiceCredentials)) .Add(credentials) End With Dim endpoint = host.AddServiceEndpoint(GetType(IMyService), binding, "") host.Open() Console.WriteLine("Service started, press ENTER to stop...") Console.ReadLine() End Using