为什么我得到这个异常。x509 证书中不存在私钥 这是为了生成一个带有 nonce+ 2 个二进制安全令牌的用户名(一个用于用户证书,一个用于服务器)。我的用户证书有一个私钥,但服务器证书没有。这是用于非对称绑定。
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.Text;
namespace MYEmedny
{
public class CustomCredentials : ClientCredentials
{
private X509Certificate2 clientAuthCert;
private X509Certificate2 clientSigningCert;
public CustomCredentials() : base() { }
public CustomCredentials(CustomCredentials other)
: base(other)
{
// other.clientSigningCert = SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "LMWARD");
clientSigningCert = other.clientSigningCert;
clientAuthCert = other.clientAuthCert;
}
protected override ClientCredentials CloneCore()
{
CustomCredentials scc = new CustomCredentials(this);
return scc;
}
public CustomCredentials(X509Certificate2 ClientAuthCert, X509Certificate2 ClientSigningCert)
: base()
{
clientAuthCert = ClientAuthCert;
clientSigningCert = ClientSigningCert;
}
public X509Certificate2 ClientAuthCert
{
get { return clientAuthCert; }
set { clientAuthCert = value; }
}
public X509Certificate2 ClientSigningCert
{
get { return clientSigningCert; }
set { clientSigningCert = value; }
}
public override SecurityTokenManager CreateSecurityTokenManager()
{
return new CustomTokenManager(this);
}
}
public class CustomTokenManager : ClientCredentialsSecurityTokenManager
{
private CustomCredentials custCreds;
public CustomTokenManager(CustomCredentials CustCreds)
: base(CustCreds)
{
custCreds = CustCreds;
}
public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
{
try
{
if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
{
x509CustomSecurityTokenProvider prov;
object temp = null;
//TransportSecurityBindingElement secBE = null;
AsymmetricSecurityBindingElement secBE = null;
if (tokenRequirement.Properties.TryGetValue("http://schemas.microsoft.com/ws/2006/05/servicemodel/securitytokenrequirement/SecurityBindingElement", out temp))
{
//secBE = (TransportSecurityBindingElement)temp;
secBE = (AsymmetricSecurityBindingElement)temp;
}
if (secBE == null)
prov = new x509CustomSecurityTokenProvider(custCreds.ClientAuthCert);
else
prov = new x509CustomSecurityTokenProvider(custCreds.ClientSigningCert);
return prov;
}
}
catch (Exception ex)
{
throw ex;
}
return base.CreateSecurityTokenProvider(tokenRequirement);
}
public override System.IdentityModel.Selectors.SecurityTokenSerializer CreateSecurityTokenSerializer(System.IdentityModel.Selectors.SecurityTokenVersion version)
{
return new CustomTokenSerializer(System.ServiceModel.Security.SecurityVersion.WSSecurity10);
}
}
class x509CustomSecurityTokenProvider : SecurityTokenProvider
{
private X509Certificate2 clientCert;
public x509CustomSecurityTokenProvider(X509Certificate2 cert)
: base()
{
clientCert = cert;
}
protected override SecurityToken GetTokenCore(TimeSpan timeout)
{
return new X509SecurityToken(clientCert);
}
}
public class CustomTokenSerializer : WSSecurityTokenSerializer
{
public CustomTokenSerializer(SecurityVersion sv) : base(sv) { }
protected override void WriteTokenCore(System.Xml.XmlWriter writer, System.IdentityModel.Tokens.SecurityToken token)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
if (token == null)
{
throw new ArgumentNullException("token");
}
if (token.GetType() == new UserNameSecurityToken("x", "y").GetType())
{
UserNameSecurityToken userToken = token as UserNameSecurityToken;
if (userToken == null)
{
throw new ArgumentNullException("userToken: " + token.ToString());
}
string tokennamespace = "wsse";
DateTime created = DateTime.Now;
string createdStr = created.ToString("yyyy-MM-ddThh:mm:ss.fffZ");
string phrase = Guid.NewGuid().ToString();
string nonce = GetSHA1String(phrase);
string password = userToken.Password;
//string password = userToken.Password;
writer.WriteStartElement(tokennamespace, "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteAttributeString("wsu", "Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", token.Id);
writer.WriteElementString(tokennamespace, "Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", userToken.UserName);
writer.WriteStartElement(tokennamespace, "Password", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
writer.WriteValue(password);
writer.WriteEndElement();
writer.WriteStartElement(tokennamespace, "Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteAttributeString("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
writer.WriteValue(nonce);
writer.WriteEndElement();
writer.WriteElementString(tokennamespace, "Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", createdStr);
writer.WriteEndElement();
writer.Flush();
}
else
{
base.WriteTokenCore(writer, token);
}
}
protected string GetSHA1String(string phrase)
{
SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
byte[] hashedDataBytes = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase));
return Convert.ToBase64String(hashedDataBytes);
}
}//CustomTokenSerializer
}
这就是我使用它的方式
private CustomBinding GetCustomBinding()
{
AsymmetricSecurityBindingElement secBE = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement
(
MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10
);
secBE.ProtectTokens = false;
X509SecurityTokenParameters x509ProtectionParameters = new X509SecurityTokenParameters();
x509ProtectionParameters.RequireDerivedKeys = false;
x509ProtectionParameters.X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier;
x509ProtectionParameters.ReferenceStyle = SecurityTokenReferenceStyle.Internal;
//x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
secBE.MessageSecurityVersion = System.ServiceModel.MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
secBE.InitiatorTokenParameters = x509ProtectionParameters;
secBE.RecipientTokenParameters = x509ProtectionParameters;
secBE.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
secBE.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
secBE.EnableUnsecuredResponse = true;
secBE.SetKeyDerivation(false);
secBE.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.TripleDesRsa15;
secBE.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
secBE.ProtectTokens = true;
// secBE.in = SecurityTokenInclusionMode.Never, RequireDerivedKeys = false );
secBE.EnableUnsecuredResponse = true;
secBE.IncludeTimestamp = false;
TextMessageEncodingBindingElement textEncBE = new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressing10, System.Text.Encoding.UTF8);
HttpsTransportBindingElement httpsBE = new HttpsTransportBindingElement();
httpsBE.RequireClientCertificate = true;
CustomBinding myBinding = new CustomBinding();
myBinding.Elements.Add(secBE);
myBinding.Elements.Add(textEncBE);
myBinding.Elements.Add(httpsBE);
return myBinding;
}
ProxyGeneration.MHSClient proxy = new ProxyGeneration.MHSClient(GetCustomBinding(), new EndpointAddress(new Uri("https://service100.emedny.org:9047/MHService"), EndpointIdentity.CreateDnsIdentity("DPMedsHistory"), new AddressHeaderCollection()));
var vs = proxy.Endpoint.Behaviors.Where((i) => i.GetType().Namespace.Contains("VisualStudio"));
proxy.Endpoint.Behaviors.Remove((System.ServiceModel.Description.IEndpointBehavior)vs.Single());
proxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName,"User");
proxy.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindBySubjectName, "Server");
proxy.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
proxy.Endpoint.Behaviors.Add(new CustomCredentials(GetCertificateFromStore("User"), GetCertificateFromStore("Server")));
proxy.ClientCredentials.UserName.UserName = "User1";
proxy.ClientCredentials.UserName.Password = "PWD";