Aracılığıyla paylaş


Nasıl yapılır: Bir X.509 Sertifikasının Şifreleme Sağlayıcısını Değiştirme

Bu konuda, X.509 sertifikasının özel anahtarını sağlamak için kullanılan şifreleme sağlayıcısının nasıl değiştireceği ve sağlayıcının Windows Communication Foundation (WCF) güvenlik çerçevesiyle nasıl tümleştireceği gösterilmektedir. Sertifikaları kullanma hakkında daha fazla bilgi için bkz . Sertifikalarla Çalışma.

WCF güvenlik çerçevesi, Nasıl yapılır: Özel Belirteç Oluşturma bölümünde açıklandığı gibi yeni güvenlik belirteci türlerini tanıtmak için bir yol sağlar. Sistem tarafından sağlanan mevcut belirteç türlerini değiştirmek için özel belirteç kullanmak da mümkündür.

Bu konu başlığında, sistem tarafından sağlanan X.509 güvenlik belirtecinin yerini sertifika özel anahtarı için farklı bir uygulama sağlayan özel bir X.509 belirteci alır. Bu, gerçek özel anahtarın varsayılan Windows şifreleme sağlayıcısından farklı bir şifreleme sağlayıcısı tarafından sağlandığı senaryolarda kullanışlıdır. Alternatif şifreleme sağlayıcısına örnek olarak, tüm özel anahtarla ilgili şifreleme işlemlerini gerçekleştiren ve özel anahtarları bellekte depolamayan ve böylece sistemin güvenliğini geliştiren bir donanım güvenlik modülü örnek olarak gösteriliyor.

Aşağıdaki örnek yalnızca tanıtım amaçlıdır. Varsayılan Windows şifreleme sağlayıcısının yerini almaz, ancak böyle bir sağlayıcının nerede tümleştirilebileceğini gösterir.

Yordamlar

İlişkili bir güvenlik anahtarı veya anahtarı olan her güvenlik belirteci, güvenlik belirteci örneğinden bir anahtar koleksiyonu döndüren özelliğini uygulamalıdır SecurityKeys . Belirteç bir X.509 güvenlik belirteciyse, koleksiyon sertifikayla ilişkili hem genel hem de özel anahtarları temsil eden sınıfının tek bir örneğini X509AsymmetricSecurityKey içerir. Sertifikanın anahtarlarını sağlamak için kullanılan varsayılan şifreleme sağlayıcısını değiştirmek için bu sınıfın yeni bir uygulamasını oluşturun.

Özel X.509 asimetrik anahtarı oluşturmak için

  1. sınıfından X509AsymmetricSecurityKey türetilmiş yeni bir sınıf tanımlayın.

  2. KeySize Salt okunur özelliğini geçersiz kılın. Bu özellik sertifikanın ortak/özel anahtar çiftinin gerçek anahtar boyutunu döndürür.

  3. DecryptKey yöntemini geçersiz kılın. Bu yöntem, sertifikanın özel anahtarıyla bir simetrik anahtarın şifresini çözmek için WCF güvenlik çerçevesi tarafından çağrılır. (Anahtar daha önce sertifikanın ortak anahtarıyla şifrelendi.)

  4. GetAsymmetricAlgorithm yöntemini geçersiz kılın. Bu yöntem, yöntemine geçirilen parametrelere bağlı olarak sertifikanın AsymmetricAlgorithm özel veya ortak anahtarı için şifreleme sağlayıcısını temsil eden sınıfın bir örneğini almak için WCF güvenlik çerçevesi tarafından çağrılır.

  5. isteğe bağlı. GetHashAlgorithmForSignature yöntemini geçersiz kılın. Sınıfın farklı bir uygulaması HashAlgorithm gerekiyorsa bu yöntemi geçersiz kılın.

  6. GetSignatureFormatter yöntemini geçersiz kılın. Bu yöntem, sertifikanın AsymmetricSignatureFormatter özel anahtarıyla ilişkili sınıfın bir örneğini döndürür.

  7. IsSupportedAlgorithm yöntemini geçersiz kılın. Bu yöntem, güvenlik anahtarı uygulaması tarafından belirli bir şifreleme algoritmasının desteklenip desteklenmediğini belirtmek için kullanılır.

    class CustomX509AsymmetricSecurityKey : X509AsymmetricSecurityKey
    {
        X509Certificate2 certificate;
        object thisLock = new Object();
        bool privateKeyAvailabilityDetermined;
        AsymmetricAlgorithm privateKey;
        PublicKey publicKey;
    
        public CustomX509AsymmetricSecurityKey(X509Certificate2 certificate)
            : base(certificate)
        {
            this.certificate = certificate;
        }
    
        public override int KeySize
        {
            get { return this.PublicKey.Key.KeySize; }
        }
    
        AsymmetricAlgorithm PrivateKey
        {
            // You need to modify this to obtain the private key using a different cryptographic
            // provider if you do not want to use the default provider.
            get
            {
                if (!this.privateKeyAvailabilityDetermined)
                {
                    lock (ThisLock)
                    {
                        if (!this.privateKeyAvailabilityDetermined)
                        {
                            this.privateKey = this.certificate.PrivateKey;
                            this.privateKeyAvailabilityDetermined = true;
                        }
                    }
                }
                return this.privateKey;
            }
        }
    
        PublicKey PublicKey
        {
            get
            {
                if (this.publicKey == null)
                {
                    lock (ThisLock)
                    {
                        this.publicKey ??= this.certificate.PublicKey;
                    }
                }
                return this.publicKey;
            }
        }
    
        Object ThisLock
        {
            get
            {
                return thisLock;
            }
        }
    
        public override byte[] DecryptKey(string algorithm, byte[] keyData)
        {
            // You can decrypt the key only if you have the private key in the certificate.
            if (this.PrivateKey == null)
            {
                throw new NotSupportedException("Missing private key");
            }
    
            RSA rsa = this.PrivateKey as RSA;
            if (rsa == null)
            {
                throw new NotSupportedException("Private key cannot be used with RSA algorithm");
            }
    
            // Support exchange keySpec, AT_EXCHANGE ?
            if (rsa.KeyExchangeAlgorithm == null)
            {
                throw new NotSupportedException("Private key does not support key exchange");
            }
    
            switch (algorithm)
            {
                case EncryptedXml.XmlEncRSA15Url:
                    return EncryptedXml.DecryptKey(keyData, rsa, false);
    
                case EncryptedXml.XmlEncRSAOAEPUrl:
                    return EncryptedXml.DecryptKey(keyData, rsa, true);
    
                default:
                    throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm));
            }
        }
    
        public override AsymmetricAlgorithm GetAsymmetricAlgorithm(string algorithm, bool privateKey)
        {
            if (privateKey)
            {
                if (this.PrivateKey == null)
                {
                    throw new NotSupportedException("Missing private key");
                }
    
                switch (algorithm)
                {
                    case SignedXml.XmlDsigDSAUrl:
                        if ((this.PrivateKey as DSA) != null)
                        {
                            return (this.PrivateKey as DSA);
                        }
                        throw new NotSupportedException("Private key cannot be used with DSA");
    
                    case SignedXml.XmlDsigRSASHA1Url:
                    case EncryptedXml.XmlEncRSA15Url:
                    case EncryptedXml.XmlEncRSAOAEPUrl:
                        if ((this.PrivateKey as RSA) != null)
                        {
                            return (this.PrivateKey as RSA);
                        }
                        throw new NotSupportedException("Private key cannot be used with RSA");
                    default:
                        throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm));
                }
            }
            else
            {
                switch (algorithm)
                {
                    case SignedXml.XmlDsigDSAUrl:
                        if ((this.PublicKey.Key as DSA) != null)
                        {
                            return (this.PublicKey.Key as DSA);
                        }
                        throw new NotSupportedException("Public key cannot be used with DSA");
                    case SignedXml.XmlDsigRSASHA1Url:
                    case EncryptedXml.XmlEncRSA15Url:
                    case EncryptedXml.XmlEncRSAOAEPUrl:
                        if ((this.PublicKey.Key as RSA) != null)
                        {
                            return (this.PublicKey.Key as RSA);
                        }
                        throw new NotSupportedException("Public key cannot be used with RSA");
                    default:
                        throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm));
                }
            }
        }
    
        public override HashAlgorithm GetHashAlgorithmForSignature(string algorithm)
        {
            if (!this.IsSupportedAlgorithm(algorithm))
            {
                throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm));
            }
    
            switch (algorithm)
            {
                case SignedXml.XmlDsigDSAUrl:
                case SignedXml.XmlDsigRSASHA1Url:
                    return new SHA1Managed();
                default:
                    throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm));
            }
        }
    
        public override AsymmetricSignatureFormatter GetSignatureFormatter(string algorithm)
        {
            // The signature can be created only if the private key is present.
            if (this.PrivateKey == null)
            {
                throw new NotSupportedException("Private key is missing");
            }
    
            // Only one of the two algorithms is supported, not both.
            //     XmlDsigDSAUrl = "http://www.w3.org/2000/09/xmldsig#dsa-sha1";
            //     XmlDsigRSASHA1Url = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
            switch (algorithm)
            {
                case SignedXml.XmlDsigDSAUrl:
    
                    // Ensure that this is a DSA algorithm object.
                    DSA dsa = (this.PrivateKey as DSA);
                    if (dsa == null)
                    {
                        throw new NotSupportedException("Private key cannot be used DSA");
                    }
    
                    return new DSASignatureFormatter(dsa);
    
                case SignedXml.XmlDsigRSASHA1Url:
                    // Ensure that this is an RSA algorithm object.
                    RSA rsa = (this.PrivateKey as RSA);
                    if (rsa == null)
                    {
                        throw new NotSupportedException("Private key cannot be used RSA");
                    }
    
                    return new RSAPKCS1SignatureFormatter(rsa);
                default:
                    throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm));
            }
        }
    
        public override bool IsSupportedAlgorithm(string algorithm)
        {
            switch (algorithm)
            {
                case SignedXml.XmlDsigDSAUrl:
                    return (this.PublicKey.Key is DSA);
    
                case SignedXml.XmlDsigRSASHA1Url:
                case EncryptedXml.XmlEncRSA15Url:
                case EncryptedXml.XmlEncRSAOAEPUrl:
                    return (this.PublicKey.Key is RSA);
    
                default:
                    return false;
            }
        }
    }
    
    Friend Class CustomX509AsymmetricSecurityKey
        Inherits X509AsymmetricSecurityKey
    
        Private _certificate As X509Certificate2
        Private _thisLock As New Object()
        Private _privateKeyAvailabilityDetermined As Boolean
        Private _privateKey As AsymmetricAlgorithm
        Private _publicKey As PublicKey
    
        Public Sub New(ByVal certificate As X509Certificate2)
            MyBase.New(certificate)
            Me._certificate = certificate
        End Sub
    
        Public Overrides ReadOnly Property KeySize() As Integer
            Get
                Return Me.PublicKey.Key.KeySize
            End Get
        End Property
    
        Private Overloads ReadOnly Property PrivateKey() As AsymmetricAlgorithm
            ' You need to modify this to obtain the private key using a different cryptographic
            ' provider if you do not want to use the default provider.
            Get
                If Not Me._privateKeyAvailabilityDetermined Then
                    SyncLock ThisLock
                        If Not Me._privateKeyAvailabilityDetermined Then
                            Me._privateKey = Me._certificate.PrivateKey
                            Me._privateKeyAvailabilityDetermined = True
                        End If
                    End SyncLock
                End If
                Return Me._privateKey
            End Get
        End Property
    
        Private Overloads ReadOnly Property PublicKey() As PublicKey
            Get
                If Me._publicKey Is Nothing Then
                    SyncLock ThisLock
                        If Me._publicKey Is Nothing Then
                            Me._publicKey = Me._certificate.PublicKey
                        End If
                    End SyncLock
                End If
                Return Me._publicKey
            End Get
        End Property
    
        Private Overloads ReadOnly Property ThisLock() As Object
            Get
                Return _thisLock
            End Get
        End Property
    
        Public Overrides Function DecryptKey(ByVal algorithm As String, _
                                             ByVal keyData() As Byte) As Byte()
            ' You can decrypt the key only if you have the private key in the certificate.
            If Me.PrivateKey Is Nothing Then
                Throw New NotSupportedException("Missing private key")
            End If
    
            Dim rsa = TryCast(Me.PrivateKey, RSA)
            If rsa Is Nothing Then
                Throw New NotSupportedException("Private key cannot be used with RSA algorithm")
            End If
    
            ' Support exchange keySpec, AT_EXCHANGE ?
            If rsa.KeyExchangeAlgorithm Is Nothing Then
                Throw New NotSupportedException("Private key does not support key exchange")
            End If
    
            Select Case algorithm
                Case EncryptedXml.XmlEncRSA15Url
                    Return EncryptedXml.DecryptKey(keyData, rsa, False)
    
                Case EncryptedXml.XmlEncRSAOAEPUrl
                    Return EncryptedXml.DecryptKey(keyData, rsa, True)
    
                Case Else
                    Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm))
            End Select
        End Function
    
        Public Overrides Function GetAsymmetricAlgorithm(ByVal algorithm As String, _
                                                         ByVal privateKey As Boolean) As AsymmetricAlgorithm
            If privateKey Then
                If Me.PrivateKey Is Nothing Then
                    Throw New NotSupportedException("Missing private key")
                End If
    
                Select Case algorithm
                    Case SignedXml.XmlDsigDSAUrl
                        If TryCast(Me.PrivateKey, DSA) IsNot Nothing Then
                            Return (TryCast(Me.PrivateKey, DSA))
                        End If
                        Throw New NotSupportedException("Private key cannot be used with DSA")
    
                    Case SignedXml.XmlDsigRSASHA1Url, EncryptedXml.XmlEncRSA15Url, EncryptedXml.XmlEncRSAOAEPUrl
                        If TryCast(Me.PrivateKey, RSA) IsNot Nothing Then
                            Return (TryCast(Me.PrivateKey, RSA))
                        End If
                        Throw New NotSupportedException("Private key cannot be used with RSA")
                    Case Else
                        Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm))
                End Select
            Else
                Select Case algorithm
                    Case SignedXml.XmlDsigDSAUrl
                        If TryCast(Me.PublicKey.Key, DSA) IsNot Nothing Then
                            Return (TryCast(Me.PublicKey.Key, DSA))
                        End If
                        Throw New NotSupportedException("Public key cannot be used with DSA")
                    Case SignedXml.XmlDsigRSASHA1Url, EncryptedXml.XmlEncRSA15Url, EncryptedXml.XmlEncRSAOAEPUrl
                        If TryCast(Me.PublicKey.Key, RSA) IsNot Nothing Then
                            Return (TryCast(Me.PublicKey.Key, RSA))
                        End If
                        Throw New NotSupportedException("Public key cannot be used with RSA")
                    Case Else
                        Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm))
                End Select
            End If
        End Function
    
        Public Overrides Function GetHashAlgorithmForSignature(ByVal algorithm As String) As HashAlgorithm
            If Not Me.IsSupportedAlgorithm(algorithm) Then
                Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm))
            End If
    
            Select Case algorithm
                Case SignedXml.XmlDsigDSAUrl, SignedXml.XmlDsigRSASHA1Url
                    Return New SHA1Managed()
                Case Else
                    Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm))
            End Select
        End Function
    
        Public Overrides Function GetSignatureFormatter(ByVal algorithm As String) As AsymmetricSignatureFormatter
            ' The signature can be created only if the private key is present.
            If Me.PrivateKey Is Nothing Then
                Throw New NotSupportedException("Private key is missing")
            End If
    
            ' Only one of the two algorithms is supported, not both.
            '     XmlDsigDSAUrl = "http://www.w3.org/2000/09/xmldsig#dsa-sha1";
            '     XmlDsigRSASHA1Url = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
            Select Case algorithm
                Case SignedXml.XmlDsigDSAUrl
    
                    ' Ensure that this is a DSA algorithm object.
                    Dim dsa = (TryCast(Me.PrivateKey, DSA))
                    If dsa Is Nothing Then
                        Throw New NotSupportedException("Private key cannot be used DSA")
                    End If
    
                    Return New DSASignatureFormatter(dsa)
    
                Case SignedXml.XmlDsigRSASHA1Url
                    ' Ensure that this is an RSA algorithm object.
                    Dim rsa = (TryCast(Me.PrivateKey, RSA))
                    If rsa Is Nothing Then
                        Throw New NotSupportedException("Private key cannot be used RSA")
                    End If
    
                    Return New RSAPKCS1SignatureFormatter(rsa)
                Case Else
                    Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm))
            End Select
        End Function
    
        Public Overrides Function IsSupportedAlgorithm(ByVal algorithm As String) As Boolean
            Select Case algorithm
                Case SignedXml.XmlDsigDSAUrl
                    Return (TypeOf Me.PublicKey.Key Is DSA)
    
                Case SignedXml.XmlDsigRSASHA1Url, EncryptedXml.XmlEncRSA15Url, EncryptedXml.XmlEncRSAOAEPUrl
                    Return (TypeOf Me.PublicKey.Key Is RSA)
    
                Case Else
                    Return False
            End Select
        End Function
    
    End Class
    

Aşağıdaki yordamda, sistem tarafından sağlanan X.509 güvenlik belirtecini değiştirmek için önceki yordamda oluşturulan özel X.509 asimetrik güvenlik anahtarı uygulamasını WCF güvenlik çerçevesiyle nasıl tümleştirileceği gösterilmektedir.

Sistem tarafından sağlanan X.509 güvenlik belirtecini özel bir X.509 asimetrik güvenlik anahtarı belirteci ile değiştirmek için

  1. Aşağıdaki örnekte gösterildiği gibi sistem tarafından sağlanan güvenlik anahtarı yerine özel X.509 asimetrik güvenlik anahtarını döndüren özel bir X.509 güvenlik belirteci oluşturun. Özel güvenlik belirteçleri hakkında daha fazla bilgi için bkz . Nasıl yapılır: Özel Belirteç Oluşturma.

    class CustomX509SecurityToken : X509SecurityToken
    {
        ReadOnlyCollection<SecurityKey> securityKeys;
        public CustomX509SecurityToken(X509Certificate2 certificate)
            : base(certificate)
        {
        }
    
        public override ReadOnlyCollection<SecurityKey> SecurityKeys
        {
            get
            {
                if (this.securityKeys == null)
                {
                    List<SecurityKey> temp = new List<SecurityKey>(1);
                    temp.Add(new CustomX509AsymmetricSecurityKey(this.Certificate));
                    this.securityKeys = temp.AsReadOnly();
                }
                return this.securityKeys;
            }
        }
    }
    
    Friend Class CustomX509SecurityToken
        Inherits X509SecurityToken
    
        Private _securityKeys As ReadOnlyCollection(Of SecurityKey)
    
        Public Sub New(ByVal certificate As X509Certificate2)
            MyBase.New(certificate)
        End Sub
    
        Public Overrides ReadOnly Property SecurityKeys() As ReadOnlyCollection(Of SecurityKey)
            Get
                If Me._securityKeys Is Nothing Then
                    Dim temp As New List(Of SecurityKey)(1)
                    temp.Add(New CustomX509AsymmetricSecurityKey(Me.Certificate))
                    Me._securityKeys = temp.AsReadOnly()
                End If
                Return Me._securityKeys
            End Get
        End Property
    
    End Class
    
  2. Örnekte gösterildiği gibi özel bir X.509 güvenlik belirteci döndüren bir özel güvenlik belirteci sağlayıcısı oluşturun. Özel güvenlik belirteci sağlayıcıları hakkında daha fazla bilgi için bkz . Nasıl yapılır: Özel Güvenlik Belirteci Sağlayıcısı Oluşturma.

    class CustomX509SecurityTokenProvider : SecurityTokenProvider
    {
        X509Certificate2 certificate;
    
        public CustomX509SecurityTokenProvider(X509Certificate2 certificate)
        {
            this.certificate = certificate;
        }
    
        protected override SecurityToken GetTokenCore(TimeSpan timeout)
        {
            return new CustomX509SecurityToken(certificate);
        }
    }
    
    Friend Class CustomX509SecurityTokenProvider
        Inherits SecurityTokenProvider
    
        Private _certificate As X509Certificate2
    
        Public Sub New(ByVal certificate As X509Certificate2)
            Me._certificate = certificate
        End Sub
    
        Protected Overrides Function GetTokenCore(ByVal timeout As TimeSpan) As SecurityToken
            Return New CustomX509SecurityToken(_certificate)
        End Function
    End Class
    
  3. Özel güvenlik anahtarının başlatıcı tarafında kullanılması gerekiyorsa, aşağıdaki örnekte gösterildiği gibi özel bir istemci güvenlik belirteci yöneticisi ve özel istemci kimlik bilgileri sınıfları oluşturun. Özel istemci kimlik bilgileri ve istemci güvenlik belirteci yöneticileri hakkında daha fazla bilgi için bkz . İzlenecek Yol: Özel İstemci ve Hizmet Kimlik Bilgileri Oluşturma.

    class CustomClientSecurityTokenManager : ClientCredentialsSecurityTokenManager
    {
        CustomClientCredentials credentials;
    
        public CustomClientSecurityTokenManager(CustomClientCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }
    
        public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
        {
            SecurityTokenProvider result = null;
    
            if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
            {
                MessageDirection direction = tokenRequirement.GetProperty<MessageDirection>(ServiceModelSecurityTokenRequirement.MessageDirectionProperty);
                if (direction == MessageDirection.Output)
                {
                    if (tokenRequirement.KeyUsage == SecurityKeyUsage.Signature)
                    {
                        result = new CustomX509SecurityTokenProvider(credentials.ClientCertificate.Certificate);
                    }
                }
                else
                {
                    if (tokenRequirement.KeyUsage == SecurityKeyUsage.Exchange)
                    {
                        result = new CustomX509SecurityTokenProvider(credentials.ClientCertificate.Certificate);
                    }
                }
            }
    
            result ??= base.CreateSecurityTokenProvider(tokenRequirement);
            return result;
        }
    }
    
    Friend Class CustomClientSecurityTokenManager
        Inherits ClientCredentialsSecurityTokenManager
    
        Private credentials As CustomClientCredentials
    
        Public Sub New(ByVal credentials As CustomClientCredentials)
            MyBase.New(credentials)
            Me.credentials = credentials
        End Sub
    
        Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) _
        As SecurityTokenProvider
            Dim result As SecurityTokenProvider = Nothing
    
            If tokenRequirement.TokenType = SecurityTokenTypes.X509Certificate Then
                Dim direction = tokenRequirement.GetProperty(Of MessageDirection) _
                (ServiceModelSecurityTokenRequirement.MessageDirectionProperty)
                If direction = MessageDirection.Output Then
                    If tokenRequirement.KeyUsage = SecurityKeyUsage.Signature Then
                        result = New CustomX509SecurityTokenProvider(credentials.ClientCertificate.Certificate)
                    End If
                Else
                    If tokenRequirement.KeyUsage = SecurityKeyUsage.Exchange Then
                        result = New CustomX509SecurityTokenProvider(credentials.ClientCertificate.Certificate)
                    End If
                End If
            End If
    
            If result Is Nothing Then
                result = MyBase.CreateSecurityTokenProvider(tokenRequirement)
            End If
            Return result
        End Function
    End Class
    
    public class CustomClientCredentials : ClientCredentials
    {
        public CustomClientCredentials()
        {
        }
    
        protected CustomClientCredentials(CustomClientCredentials other)
            : base(other)
        {
        }
    
        protected override ClientCredentials CloneCore()
        {
            return new CustomClientCredentials(this);
        }
    
        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return new CustomClientSecurityTokenManager(this);
        }
    }
    
    Public Class CustomClientCredentials
        Inherits ClientCredentials
    
        Public Sub New()
        End Sub
    
        Protected Sub New(ByVal other As CustomClientCredentials)
            MyBase.New(other)
        End Sub
    
        Protected Overrides Function CloneCore() As ClientCredentials
            Return New CustomClientCredentials(Me)
        End Function
    
        Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager
            Return New CustomClientSecurityTokenManager(Me)
        End Function
    End Class
    
  4. Özel güvenlik anahtarının alıcı tarafında kullanılması gerekiyorsa, aşağıdaki örnekte gösterildiği gibi bir özel hizmet güvenlik belirteci yöneticisi ve özel hizmet kimlik bilgileri oluşturun. Özel hizmet kimlik bilgileri ve hizmet güvenlik belirteci yöneticileri hakkında daha fazla bilgi için bkz . İzlenecek Yol: Özel İstemci ve Hizmet Kimlik Bilgileri Oluşturma.

    class CustomServiceSecurityTokenManager : ServiceCredentialsSecurityTokenManager
    {
        CustomServiceCredentials credentials;
    
        public CustomServiceSecurityTokenManager(CustomServiceCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }
    
        public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
        {
            SecurityTokenProvider result = null;
    
            if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
            {
                MessageDirection direction = tokenRequirement.GetProperty<MessageDirection>(ServiceModelSecurityTokenRequirement.MessageDirectionProperty);
                if (direction == MessageDirection.Input)
                {
                    if (tokenRequirement.KeyUsage == SecurityKeyUsage.Exchange)
                    {
                        result = new CustomX509SecurityTokenProvider(credentials.ServiceCertificate.Certificate);
                    }
                }
                else
                {
                    if (tokenRequirement.KeyUsage == SecurityKeyUsage.Signature)
                    {
                        result = new CustomX509SecurityTokenProvider(credentials.ServiceCertificate.Certificate);
                    }
                }
            }
    
            result ??= base.CreateSecurityTokenProvider(tokenRequirement);
            return result;
        }
    }
    
    Friend Class CustomServiceSecurityTokenManager
        Inherits ServiceCredentialsSecurityTokenManager
    
        Private credentials As CustomServiceCredentials
    
        Public Sub New(ByVal credentials As CustomServiceCredentials)
            MyBase.New(credentials)
            Me.credentials = credentials
        End Sub
    
        Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) As SecurityTokenProvider
            Dim result As SecurityTokenProvider = Nothing
    
            If tokenRequirement.TokenType = SecurityTokenTypes.X509Certificate Then
                Dim direction = tokenRequirement.GetProperty(Of MessageDirection) _
                (ServiceModelSecurityTokenRequirement.MessageDirectionProperty)
                If direction = MessageDirection.Input Then
                    If tokenRequirement.KeyUsage = SecurityKeyUsage.Exchange Then
                        result = New CustomX509SecurityTokenProvider(credentials.ServiceCertificate.Certificate)
                    End If
                Else
                    If tokenRequirement.KeyUsage = SecurityKeyUsage.Signature Then
                        result = New CustomX509SecurityTokenProvider(credentials.ServiceCertificate.Certificate)
                    End If
                End If
            End If
    
            If result Is Nothing Then
                result = MyBase.CreateSecurityTokenProvider(tokenRequirement)
            End If
            Return result
        End Function
    End Class
    
    public class CustomServiceCredentials : ServiceCredentials
    {
        public CustomServiceCredentials()
        {
        }
    
        protected CustomServiceCredentials(CustomServiceCredentials other)
            : base(other)
        {
        }
    
        protected override ServiceCredentials CloneCore()
        {
            return new CustomServiceCredentials(this);
        }
    
        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return new CustomServiceSecurityTokenManager(this);
        }
    }
    
    Public Class CustomServiceCredentials
        Inherits ServiceCredentials
    
        Public Sub New()
        End Sub
    
        Protected Sub New(ByVal other As CustomServiceCredentials)
            MyBase.New(other)
        End Sub
    
        Protected Overrides Function CloneCore() As ServiceCredentials
            Return New CustomServiceCredentials(Me)
        End Function
    
        Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager
            Return New CustomServiceSecurityTokenManager(Me)
        End Function
    
    End Class
    

Ayrıca bkz.