Reputation: 25327
Here's my WCF service code:
ServiceHost svh = new ServiceHost(typeof(MyClass));
var tcpbinding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential, true);
//security
tcpbinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
svh.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new BWUserNamePasswordValidator();
svh.Credentials.UserNameAuthentication.UserNamePasswordValidationMode =UserNamePasswordValidationMode.Custom;
svh.Credentials.ServiceCertificate.Certificate = GenerateCertificate(myCert);
svh.AddServiceEndpoint(typeof(IMyClass), tcpbinding, location);
svh.Open();
And here's the code, which I'm using to generate the certificate:
static X509Certificate2 GenerateCertificate(string certName)
{
var keypairgen = new RsaKeyPairGenerator();
keypairgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 1024));
var keypair = keypairgen.GenerateKeyPair();
var gen = new X509V3CertificateGenerator();
var CN = new X509Name("CN=" + certName);
var SN = BigInteger.ProbablePrime(120, new Random());
gen.SetSerialNumber(SN);
gen.SetSubjectDN(CN);
gen.SetIssuerDN(CN);
gen.SetNotAfter(DateTime.MaxValue);
gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
gen.SetSignatureAlgorithm("MD5WithRSA");
gen.SetPublicKey(keypair.Public);
gen.AddExtension(X509Extensions.SubjectKeyIdentifier, false,
new SubjectKeyIdentifierStructure(keypair.Public));
var newCert = gen.Generate(keypair.Private);
return new X509Certificate2(DotNetUtilities.ToX509Certificate((Org.BouncyCastle.X509.X509Certificate)newCert));
}
When I'm starting the server it crashes with following exception:
ArgumentException: It is likely that certificate 'CN=MyCert' may not
have a private key that is capable of key exchange or the process may not have
access rights for the private key. Please see inner exception for detail.
The inner exception is null.
What did I do wrong?
Upvotes: 1
Views: 2811
Reputation: 28338
Key pairs used for certificate exchange need to be created explicitly for that purpose. I think you just need to add another extension to your certificate generator like this:
gen.AddExtension(
X509Extensions.KeyUsage,
true,
new KeyUsage(KeyUsage.keyCertSign));
Not sure if that syntax is exactly correct but that's the idea: you need to make the key in the certificate as being for certificate signing, and that is a "critical" extension if present.
Upvotes: 2