Mutual authentication using pkcs12 certificate in java client with weblogic server - authentication

I am not able to get mbeans from Weblogic server using PKCS12 ssl certificate through Java client.
Server: Weblogic
Client: Java client/JConsole
Server side commands used to create self signed certificates:
Created a certificate using the Weblogic CertGen utility, Weblogic CertGenCA.der and the Certificate Authority.
java utils.CertGen -certfile ServerCert -keyfile ServerKey -keyfilepass keypass
java utils.der2pem CertGenCA.der
type serverCert.pem CertGenCA.pem >> myCert.pem
Server Keystore created>>
java utils.ImportPrivateKey -keystore SeverIdentity.jks -storepass storepass -storetype JKS \
-keypass keypass -alias mykey -certfile myCert.pem -keyfile ServerKey.pem \
-keyfilepass keypass
Server Truststore used>>
DemoTrust.jks (Default Weblogic truststore)
Client side commands used to create PKCS12 self signed certificate:
java utils.CertGen -certfile ClientCert -keyfile ClientKey -keyfilepass keypass
openssl pkcs12 -export -in ClientCert.pem -inkey ClientKey.pem -out client-pkcs-12-cert
Configurations done in Weblogic Admin Console:
Keystores: Custom Identity Custom Trust.
Custom Identity Keystore: D:\certificate\latest\pkcs\SeverIdentity.jks
Custom Identity Keystore Type: JKS
Custom Identity Keystore Passphrase: storepass (same as –storepass value of ImportPrivateKey)
Confirm Custom Identity Keystore Passphrase: storepass
Custom Trust Keystore: D:\certificate\latest\pkcs\DemoTrust.jks
Custom Trust Keystore Type: JKS
Custom Trust Keystore Passphrase: DemoTrustKeyStorePassPhrase
Custom Trust Keystore Passphrase: DemoTrustKeyStorePassPhrase
Configurations done in setDomainEnv.cmd:
set JAVA_OPTIONS=%JAVA_OPTIONS% -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9191 \
-Dcom.sun.management.jmxremote.ssl=true -Dcom.sun.management.jmxremote.authenticate=false \
-Djavax.net.ssl.keyStore=D:\certificate\latest\pkcs\SeverIdentity.jks \
-Djavax.net.ssl.keyStorePassword=keypass -Djavax.net.ssl.trustStore=D:\certificate\latest\pkcs\DemoTrust.jks \
-Djavax.net.ssl.trustStorePassword=DemoTrustKeyStorePassPhrase -Djava.rmi.server.hostname=10.112.69.200
Reference : http://www.weblogic-tips.com/2010/05/20/two-way-ssl-on-weblogic-server/
Java client code:
public static void main22(String args[]) {
try {
System.setProperty("javax.net.ssl.keyStore",
"D://certificate//latest//client-pkcs-12-cert");
System.setProperty("javax.net.ssl.keyStorePassword", "keypass");
HashMap<String, Object> env = new HashMap<String, Object>();
String truststore = "D://certificate//latest//client-pkcs-12-cert";
char truststorepass[] = "keypass".toCharArray();
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(new FileInputStream(truststore), truststorepass);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance("SunX509");
tmf.init(ks);
SSLContext ctx = SSLContext.getInstance("TLSv1");
ctx.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory ssf = ctx.getSocketFactory();
env.put("jmx.remote.tls.socket.factory", ssf);
JMXServiceURL address = new JMXServiceURL("rmi", "", 0,
"/jndi/rmi://localhost:9191/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(address, env);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
Set<ObjectInstance> beans = mbsc.queryMBeans(null, null);
for (ObjectInstance instance : beans) {
MBeanInfo info = mbsc.getMBeanInfo(instance.getObjectName());
System.out.println(info);
}
jmxc.close();
} catch (Exception e) {
e.printStackTrace();
System.out.println("error :" + e.getMessage());
}
}
I am able to get mbeans when JKS certificate is being used but when I use PKCS12 certificate it gives the following error while connecting through JMXConnectorFactory:
Exception at line : JMXConnector jmxc = JMXConnectorFactory.connect(address, env);
Exceptions:
java.rmi.ConnectIOException: Exception creating connection to: 10.112.69.200; nested exception is:
java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:614)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:110)
at javax.management.remote.rmi.RMIServerImpl_Stub.newClient(Unknown Source)
at javax.management.remote.rmi.RMIConnector.getConnection(RMIConnector.java:2327)
at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:277)
at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:248)
at test.Test.main(Test.java:68)
Caused by: java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
at javax.net.ssl.DefaultSSLSocketFactory.throwException(SSLSocketFactory.java:179)
at javax.net.ssl.DefaultSSLSocketFactory.createSocket(SSLSocketFactory.java:192)
at javax.rmi.ssl.SslRMIClientSocketFactory.createSocket(SslRMIClientSocketFactory.java:105)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
... 8 more
Caused by: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
at java.security.Provider$Service.newInstance(Provider.java:1245)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:220)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:147)
at javax.net.ssl.SSLContext.getInstance(SSLContext.java:125)
at javax.net.ssl.SSLContext.getDefault(SSLContext.java:68)
at javax.net.ssl.SSLSocketFactory.getDefault(SSLSocketFactory.java:102)
at javax.rmi.ssl.SslRMIClientSocketFactory.getDefaultClientSocketFactory(SslRMIClientSocketFactory.java:192)
at javax.rmi.ssl.SslRMIClientSocketFactory.createSocket(SslRMIClientSocketFactory.java:102)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
at sun.rmi.transport.DGCImpl_Stub.dirty(Unknown Source)
at sun.rmi.transport.DGCClient$EndpointEntry.makeDirtyCall(DGCClient.java:342)
at sun.rmi.transport.DGCClient$EndpointEntry.registerRefs(DGCClient.java:285)
at sun.rmi.transport.DGCClient.registerRefs(DGCClient.java:121)
at sun.rmi.transport.ConnectionInputStream.registerRefs(ConnectionInputStream.java:80)
at sun.rmi.transport.StreamRemoteCall.releaseInputStream(StreamRemoteCall.java:138)
at sun.rmi.transport.StreamRemoteCall.done(StreamRemoteCall.java:292)
at sun.rmi.server.UnicastRef.done(UnicastRef.java:431)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at com.sun.jndi.rmi.registry.RegistryContext.lookup(RegistryContext.java:97)
at com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:185)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at javax.management.remote.rmi.RMIConnector.findRMIServerJNDI(RMIConnector.java:1886)
at javax.management.remote.rmi.RMIConnector.findRMIServer(RMIConnector.java:1856)
at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:255)
... 2 more
Caused by: java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:544)
at sun.security.util.DerValue.init(DerValue.java:347)
at sun.security.util.DerValue.<init>(DerValue.java:303)
at com.sun.net.ssl.internal.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1200)
at java.security.KeyStore.load(KeyStore.java:1185)
at com.sun.net.ssl.internal.ssl.TrustManagerFactoryImpl.getCacertsKeyStore(TrustManagerFactoryImpl.java:202)
at com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl.getDefaultTrustManager(DefaultSSLContextImpl.java:70)
at com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl.<init>(DefaultSSLContextImpl.java:40)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:357)
at java.lang.Class.newInstance(Class.java:310)
at java.security.Provider$Service.newInstance(Provider.java:1221)
... 28 more
error :Exception creating connection to: 10.112.69.200; nested exception is:
java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)

Firstly, ... (EDIT: I've realised I had misread part of the error, my first point was most certainly at least partly incorrect.)
A quick search for your error message (java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big. )points to this IBM support page, which suggests to use a JKS keystore instead of PKCS#12 (on the server side, which you're not doing) or that there are incorrect characters in the certificate.
Secondly, you have no chance to get client-certificate authentication working with this code, even once your server certificate problems are fixed.
String truststore = "D://certificate//latest//client-pkcs-12-cert";
char truststorepass[] = "keypass".toCharArray();
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(new FileInputStream(truststore), truststorepass);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance("SunX509");
tmf.init(ks);
SSLContext ctx = SSLContext.getInstance("TLSv1");
ctx.init(null, tmf.getTrustManagers(), null);
The PKCS#12 file should contain both your client cert and its private key. It is meant to be used as a keystore, not a truststore. That is, although the entity is called keystore in both cases, you are meant to use it with the key manager, not the trust manager.
Here, you're using your PKCS#12 file to initialise the trust manager of your SSLContext. It's the key manager you should initialise instead.
In addition, if you're using your code with a JRE that isn't related to Sun/Oracle/OpenJDK, you should probably avoid to hard-code "SunX509", use TrustManagerFactory.getDefaultAlgorthim() instead (same for the KeyManagerFactory when you implement this stage).

Related

How do I connect to GRPC using TLS?

I'm trying unsuccessfully to get a basic GRPC server and client working with SSL/TLS, with a node client and Java server. Starting with no security:
// client.js
const creds = grpc.credentials.createInsecure()
const stub = new hello_proto.Greeter('localhost:50051', creds)
stub.sayHello(...)
// server.java
Server server = ServerBuilder.forPort(50051)
.addService(serviceImplementation)
.build();
server.start();
All works as expected here. I then tried to add SSL credentials, generating a certificate and private key like this (following a Python example):
$ openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
This generates a certificate (server.crt) and private key (server.key). I then add those credentials to client and server (private key on server only), following the guidance from the grpc.io Auth Guide and grpc-java respectively:
// client.js
const rootCert = fs.readFileSync("path/to/server.crt");
const channelCreds = grpc.credentials.createSsl(rootCert);
const stub = new hello_proto.Greeter('localhost:50051', channelCreds);
stub.sayHello(...)
// server.java
File certChainFile = File("path/to/server.crt")
File privateKeyFile = File("path/to/server.key")
Server server = ServerBuilder.forPort(50051)
.useTransportSecurity(certChainFile, privateKeyFile)
.addService(serviceImplementation)
.build();
server.start();
Now I get an error UNAVAILABLE: No connection established on the client side:
Error: 14 UNAVAILABLE: No connection established
at Object.callErrorFromStatus (path/to/node_modules/#grpc/grpc-js/build/src/call.js:31:26)
at Object.onReceiveStatus (path/to/node_modules/#grpc/grpc-js/build/src/client.js:176:52)
at Object.onReceiveStatus (path/to/node_modules/#grpc/grpc-js/build/src/client-interceptors.js:336:141)
at Object.onReceiveStatus (path/to/node_modules/#grpc/grpc-js/build/src/client-interceptors.js:299:181)
at path/to/node_modules/#grpc/grpc-js/build/src/call-stream.js:130:78
at processTicksAndRejections (node:internal/process/task_queues:76:11) {
code: 14,
details: 'No connection established',
metadata: Metadata { internalRepr: Map(0) {}, options: {} }
}
No error on the server side. The client-side error is, unhelpfully, identical to the one I get when the server is down.
How do I implement basic TLS authentication between a Java server and node client?
Maybe you can reference my code in helloworlde/grpc-java-sample, feel free to translate Chinese;
For the both side, it need SslContext
Server
File keyCertChainFile = new File("server.pem");
File keyFile = new File("server.key");
SslContext sslContext = GrpcSslContexts.forServer(keyCertChainFile, keyFile)
.clientAuth(ClientAuth.OPTIONAL)
.build();
Server server = NettyServerBuilder.forAddress(new InetSocketAddress(9090))
.addService(new HelloServiceImpl())
.sslContext(sslContext)
.build();
Client
File trustCertCollectionFile = new File("server.pem");
SslContext sslContext = GrpcSslContexts.forClient()
.trustManager(trustCertCollectionFile)
.build();
ManagedChannel channel = NettyChannelBuilder.forAddress("127.0.0.1", 9090)
.overrideAuthority("localhost")
.sslContext(sslContext)
.build();

Java TooTallNate Secure Websocket Server on FireTV with Lets Encrypt Certificate: Handshake / Chain Error

I am using a Java Websocket Server (TooTallNate). A Javascript App is connecting securely via a LetsEncrypt certificate. It is renewed automatically via certbot and is serving an Apache on the same machine too. On all tested browsers everything is working fine, for both https and wss.
I wanted to submit my app as a packaged FireTV app. I tested it in the "Web App Tester" app. As soon as the JS tries to connect to the WSS, it raises an SSL error, which reads in adb-logcat
I/X509util: Failed to validate the certificate chain, error: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
but sometimes just
E/chromium(13208): [ERROR:ssl_client_socket_impl.cc(947)] handshake failed; returned -1, SSL error code 1, net_error -202
The relevant Java code filling the SSLContext from TooTallNate is:
private static SSLContext getContext() {
SSLContext context;
String password = "CHANGEIT";
String pathname = "pem";
try {
context = SSLContext.getInstance("TLS");
byte[] certBytes = parseDERFromPEM(getBytes(new File(pathname + File.separator + "cert.pem")),"-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
byte[] keyBytes = parseDERFromPEM(getBytes(new File(pathname + File.separator + "privkey.pem")),"-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----");
X509Certificate cert = generateCertificateFromDER(certBytes);
RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes);
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null);
keystore.setCertificateEntry("cert-alias", cert);
keystore.setKeyEntry("key-alias", key, password.toCharArray(), new Certificate[]{cert});
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, password.toCharArray());
KeyManager[] km = kmf.getKeyManagers();
context.init(km, null, null);
}
catch (Exception e) {
context = null;
}
return context;
}
It took some reading to get it to work. There are few information on this special problem, so I decided to answer myself:
It was truly a problem of the missing chain in the SSLContext. Couldn't believe that, because it worked on every other chromium based browser.
In my LetsEncrypt folder I have four files: privkey.pem (not at thing), cert.pem, chain.pem and fullchain.pem, where fullchain.pem is just the concatenation of chain.pem and cert.pem. cert.pem is our own certificate and chain.pem is the Digital Signature Trust DST Root CA X3 certificate which you can see yourself using:
cat chain.pem | openssl x509 -text
I compared the certificates served over https and wss using:
openssl s_client -connect myurl:443 | openssl x509 -text
and
openssl s_client -connect myurl:8080 | openssl x509 -text
The latter showed two error at the beginning of the output
verify error:num=20:unable to get local issuer certificate
while the https response from apache showed
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = myurl
verify return:1
Finally the working solution is a lot easier than my solutions I had meanwhile. Its not necessary to download any further chain certificates. Just load the chain.pem you already have in your LetsEncrypt folder like the cert.pem and add both as the chain to the keystore in the setKeyEntry function:
private static SSLContext getContext() {
SSLContext context;
String password = "CHANGEIT";
String pathname = "pem";
try {
context = SSLContext.getInstance("TLS");
byte[] certBytes = parseDERFromPEM(getBytes(new File(pathname + File.separator + "cert.pem")),"-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
byte[] chainBytes = parseDERFromPEM(getBytes(new File(pathname + File.separator + "chain.pem")),"-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
byte[] keyBytes = parseDERFromPEM(getBytes(new File(pathname + File.separator + "privkey.pem")),"-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----");
X509Certificate cert = generateCertificateFromDER(certBytes);
X509Certificate chain = generateCertificateFromDER(chainBytes);
RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes);
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null);
keystore.setCertificateEntry("cert-alias", cert);
keystore.setKeyEntry("key-alias", key, password.toCharArray(), new Certificate[]{cert, chain});
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, password.toCharArray());
KeyManager[] km = kmf.getKeyManagers();
context.init(km, null, null);
}
catch (Exception e) {
context = null;
}
return context;
}

EJB Remoting over SSL

After upgrade from WildFly-8.2, EJB remote invoke works fine on HTTP but when I set HTTPS remote connector and URL, it fails. I am invoking from a Java client using InitialContext.
Tried adding the server certificate to java truststore and client truststore but not worked. The client shown certificate unknown.
This issue fixed when loaded the keystore from client code before remote EJB call:
KeyManager[] keyManager = keyManagerFactory.getKeyManagers();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
logger.info("Load JSSE truststore ");
KeyStore trustStore = getTrustStore(userId, null);
if (trustStore == null) {
throw new RuntimeException("A truststore is required for SSL");
}
trustManagerFactory.init(trustStore);
TrustManager[] trustManager = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManager, trustManager, null);
SSLContext.setDefault(sslContext);
The following option passed on running java client not taken for EJB remote SSL call:
-Djavax.net.ssl.trustStore=/home/wf/clientw16.truststore
This way of passing truststore was working for WF-8.2.
Is this changed in WF-16 or any other settings needed?

Configuring logstash with ssl and sending message to kafka(with ssl) topic

I have logstash-6.5.4 (with ssl), web and scheduler in my local (hostname: webbox) and kafka-2.0 (with ssl) on another (hostname: kafkabox).
I am not able to receive message in kafka topic when message is sent from logstash.
Neither error message is displayed not message is sent to kafka topic. I tried to import logstash.crt into kafka's truststore but it also didn't worked.
Created logstash.crt and logstash.key with below command.
sudo openssl req -x509 -batch -nodes -days 3650 -newkey rsa:2048 -keyout /etc/logstash/logstash.key -out /etc/logstash/logstash.crt
Imported the logstash.crt into kafka's truststore file also and tried.
keytool -import -alias logstash -file logstash.crt -keystore cacerts
Logstash conf file is given below...
input {
tcp {
host=>"0.0.0.0"
port=>5514
type=>"syslogType"
ssl_enable=>true
ssl_cert=>"/etc/logstash/logstash.crt"
ssl_key=>"/etc/logstash/logstash.key"
ssl_verify=>false
}
}
filter {
}
output {
kafka {
bootstrap_servers=>"kafkabox:9093"
codec=>"json_lines"
topic_id=>"a_test"
ssl_keystore_location=>"keystore file"
ssl_keystore_password=>"changeit"
ssl_key_password=>"changeit"
ssl_truststore_location=>"truststore file"
ssl_truststore_password=>"changeit"
security_protocol=>"SSL"
}
}
Expecting message is sent from logstash (with SSL) to kafka (with SSL).
Java Code to connect to logstash which internally failing to send message to kafka topics (in ssl mode).
public class LogstashClient {
private static String message = "<86>Jun 25 14:32:25 webbox sshd[7517]: Failed password for root from 196.165.132.192 port 45691 ssh2";
public static void main(String[] args) throws Exception {
nonSSL();
//SSL();
}
private static void SSL() throws Exception {
// logstash.crt is directly imported into kafka's truststore
// Below <<Client Truststore>> will also have logstash.crt imported for handshaking while connecting
System.setProperty("javax.net.ssl.trustStore", "<<Client Truststore>>");
System.setProperty("javax.net.ssl.trustStorePassword", "test1234");
SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket("localhost", 5514);
System.out.println("Handshaking...");
socket.startHandshake();
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
boolean checkError = printWriter.checkError();
printWriter.println(message);
}
private static void nonSSL() throws Exception {
Socket socket = new Socket("localhost", 5514);
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
printWriter.println(message);
}
}
Thanks,
RK,

WebRequest with mutual authentication

Extra information at the end after comments from Crypt32 (thank you Crypt32!)
I have to send data to a server. I need mutual authentication: the server needs to be certain it is me, and I need to be certain that the server really is the server that I trust. This needs to be dons in a windows program.
To identify itself, the server will send me a certificate that is issued by certificate authorities that I trust: a root certificate and an intermediate certificate:
Root CA-G2.PEM
Intermediate CA-G2.PEM
To identify me, the organization gave me a certificate and a private key
Root CA-G3.PEM
Intermediate CA-G3.PEM
MyCertificate.CRT (= pem) and MyCertificate.Private.Key (=RSA)
I have imported all root certificates and intermediate certificates into the windows keystore.
To sent the message:
const string url = "https://...//Deliver";
HttpWebRequest webRequest = WebRequest.CreateHttp(url);
// Security:
webRequest.AuthenticationLevel=AuthenticationLevel.MutualAuthRequired;
webRequest.Credentials = CredentialCache.DefaultCredentials;
// Should I add my certificate?
X509Certificate myCertificate = new X509Certificate("MyCertificate.CRT");
// Should I add Certificate authorities?
// only the CA-G2 authorities, so my WebRequest can trust the certificate
// that will be sent by the Server?
// or Should I also add the CA-G3 who issued MyCertificate
// and what about MyCertificate.Private.Key, the RSA file?
// Fill the rest of the WebRequest:
webRequest.Method = "Post";
webRequest.Accept = "text/xml";
webRequest.Headers.Add("SOAP:Action");
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
... etc
// do the call and display the result
using (WebResponse response = webRequest.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
string soapResult = reader.ReadToEnd();
Console.WriteLine(soapResult);
}
}
The WebResponse doesn't indicate any error. The returned data is an empty (non-null) string. Yet:
response.StatusCode == NoContent (204)
soapResult == String.Empty
response.IsMutuallyAuthenticated == false
The NoContent and the empty data result are expected. Does the false IsMutuallyAuthenticated indicate that something is wrong with my authentication?
Added information
Crypt32 suggested I should convert MyCertificate.CRT and MyCertificate.Private.Key into one PFX (or P12) file.
For this I use openssl.
I concatenated the CA-G3 files into one TrustG3.Pem and created the P12 file:
openssl.exe pkcs12 -export -name "<some friendly name>"
-certfile TrustG3.Pem
-in MyCertificate.CRT
-inkey MyCertificate.Private.Key
-out MyCertificate.P12
After providing a password a proper Pkcs12 file (PFX) was created. The source code changes slightly:
HttpWebRequest webRequest = WebRequest.CreateHttp(url);
// Security:
webRequest.AuthenticationLevel=AuthenticationLevel.MutualAuthRequired;
webRequest.Credentials = CredentialCache.DefaultCredentials;
var p12Certificate = new X509Certificate("MyCertificate.P12", "my password");
webRequest.ClientCertificates.Add(p12Certificate);
Alas, this didn't help. The webResponse still says:
response.IsMutuallyAuthenticated == false
Does the false IsMutuallyAuthenticated indicate that something is wrong with my authentication?
yes, it does. Because you add only public part of client certificate. There is no associated private key specified. Either, use certificate from certificate store (assuming, cert store contains private key) or import certificate from PFX.
Update:
now your client authentication code looks correct. Next step is to check if your client certificate is trusted by server.