Trying to pass along x509 client certificate to second server











up vote
0
down vote

favorite












I'm trying to give server "A" the ability to connect to server "B" using the same X509 client certificate it received from the user. Here are the basics of where I am so far:



public int makeRemoteCall() {
URL url = new URL("https://host.com/service/request");
HttpsURLConnection conn = url.openConnection();
SSLSocketFactory factory = getFactoryFromSessionCert();
conn.setSSLSocketFactory(factory);
int responseCode = conn.getResponseCode();
return responseCode;
}


public static SSLSocketFactory getFactoryFromSessionCert() throws Exception {
HttpServletRequest request = getRequest();
X509Certificate certs = (X509Certificate)request.getAttribute("javax.servlet.request.X509Certificate");

KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setCertificateEntry("client_cert", certs[0]);

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, null);

SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, null);

return context.getSocketFactory();
}


I am able to retrieve the client's certificate without trouble, and can verify that it does indeed end up in keyStore. But the certificate doesn't seem to make it into keyManagerFactory.



I thought the issue was that I'm not providing a password in keyManagerFactory.init(keyStore, null), so I tried providing it but without success. And should I even have to? I understand that I would need a password if I were loading certificates and keys from a protected file, but here I'm just trying to pass along an already exposed public certificate.



As further background, this basic scheme works if I replace getFactoryFromSessionCert() with this:



public static SSLSocketFactory getFactory(File pKeyFile, String pKeyPassword) throws Exception {

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyInput = new FileInputStream(pKeyFile);
keyStore.load(keyInput, pKeyPassword.toCharArray());
keyInput.close();

keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
return context.getSocketFactory();
}


So, what am I not understanding? And how should I pass along a client certificate?










share|improve this question


















  • 4




    There's a lot of concepts about PKI being misused in your code. You can't use a X509Certificate without a private key to start a SSL connection, the server in the other side will never accept the handshake. If you have plans to just pass the X509 along you can set it in the header of the new request. The simple answer is... you can't reuse the mutual TLS channel in the second server because you don't have the private key to make the key exchange.
    – argoth
    Nov 19 at 21:06












  • Thanks, @argoth . I wasn't thinking of it like that, but it makes sense now. So, assuming I can make the second SSL connection with the server's own certificate, can the original client certificate be passed along to the second server in a way that satisfies client authentication? I can make your suggestion of sending it in the header work (thanks!), but what would be the proper way of solving this? I imagine it's a common need.
    – Didjit
    Nov 20 at 17:58












  • The more I think about it, the more I realize what I'm really talking about is some kind of centralized authentication. Like Kerberos, except that's overkill for my needs. I'll probably go with putting at least the essential information in the headers or a cookie, but this seems like a really bad practice in general. What would be the simplest legitimate approach?
    – Didjit
    Nov 20 at 19:41















up vote
0
down vote

favorite












I'm trying to give server "A" the ability to connect to server "B" using the same X509 client certificate it received from the user. Here are the basics of where I am so far:



public int makeRemoteCall() {
URL url = new URL("https://host.com/service/request");
HttpsURLConnection conn = url.openConnection();
SSLSocketFactory factory = getFactoryFromSessionCert();
conn.setSSLSocketFactory(factory);
int responseCode = conn.getResponseCode();
return responseCode;
}


public static SSLSocketFactory getFactoryFromSessionCert() throws Exception {
HttpServletRequest request = getRequest();
X509Certificate certs = (X509Certificate)request.getAttribute("javax.servlet.request.X509Certificate");

KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setCertificateEntry("client_cert", certs[0]);

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, null);

SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, null);

return context.getSocketFactory();
}


I am able to retrieve the client's certificate without trouble, and can verify that it does indeed end up in keyStore. But the certificate doesn't seem to make it into keyManagerFactory.



I thought the issue was that I'm not providing a password in keyManagerFactory.init(keyStore, null), so I tried providing it but without success. And should I even have to? I understand that I would need a password if I were loading certificates and keys from a protected file, but here I'm just trying to pass along an already exposed public certificate.



As further background, this basic scheme works if I replace getFactoryFromSessionCert() with this:



public static SSLSocketFactory getFactory(File pKeyFile, String pKeyPassword) throws Exception {

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyInput = new FileInputStream(pKeyFile);
keyStore.load(keyInput, pKeyPassword.toCharArray());
keyInput.close();

keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
return context.getSocketFactory();
}


So, what am I not understanding? And how should I pass along a client certificate?










share|improve this question


















  • 4




    There's a lot of concepts about PKI being misused in your code. You can't use a X509Certificate without a private key to start a SSL connection, the server in the other side will never accept the handshake. If you have plans to just pass the X509 along you can set it in the header of the new request. The simple answer is... you can't reuse the mutual TLS channel in the second server because you don't have the private key to make the key exchange.
    – argoth
    Nov 19 at 21:06












  • Thanks, @argoth . I wasn't thinking of it like that, but it makes sense now. So, assuming I can make the second SSL connection with the server's own certificate, can the original client certificate be passed along to the second server in a way that satisfies client authentication? I can make your suggestion of sending it in the header work (thanks!), but what would be the proper way of solving this? I imagine it's a common need.
    – Didjit
    Nov 20 at 17:58












  • The more I think about it, the more I realize what I'm really talking about is some kind of centralized authentication. Like Kerberos, except that's overkill for my needs. I'll probably go with putting at least the essential information in the headers or a cookie, but this seems like a really bad practice in general. What would be the simplest legitimate approach?
    – Didjit
    Nov 20 at 19:41













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I'm trying to give server "A" the ability to connect to server "B" using the same X509 client certificate it received from the user. Here are the basics of where I am so far:



public int makeRemoteCall() {
URL url = new URL("https://host.com/service/request");
HttpsURLConnection conn = url.openConnection();
SSLSocketFactory factory = getFactoryFromSessionCert();
conn.setSSLSocketFactory(factory);
int responseCode = conn.getResponseCode();
return responseCode;
}


public static SSLSocketFactory getFactoryFromSessionCert() throws Exception {
HttpServletRequest request = getRequest();
X509Certificate certs = (X509Certificate)request.getAttribute("javax.servlet.request.X509Certificate");

KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setCertificateEntry("client_cert", certs[0]);

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, null);

SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, null);

return context.getSocketFactory();
}


I am able to retrieve the client's certificate without trouble, and can verify that it does indeed end up in keyStore. But the certificate doesn't seem to make it into keyManagerFactory.



I thought the issue was that I'm not providing a password in keyManagerFactory.init(keyStore, null), so I tried providing it but without success. And should I even have to? I understand that I would need a password if I were loading certificates and keys from a protected file, but here I'm just trying to pass along an already exposed public certificate.



As further background, this basic scheme works if I replace getFactoryFromSessionCert() with this:



public static SSLSocketFactory getFactory(File pKeyFile, String pKeyPassword) throws Exception {

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyInput = new FileInputStream(pKeyFile);
keyStore.load(keyInput, pKeyPassword.toCharArray());
keyInput.close();

keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
return context.getSocketFactory();
}


So, what am I not understanding? And how should I pass along a client certificate?










share|improve this question













I'm trying to give server "A" the ability to connect to server "B" using the same X509 client certificate it received from the user. Here are the basics of where I am so far:



public int makeRemoteCall() {
URL url = new URL("https://host.com/service/request");
HttpsURLConnection conn = url.openConnection();
SSLSocketFactory factory = getFactoryFromSessionCert();
conn.setSSLSocketFactory(factory);
int responseCode = conn.getResponseCode();
return responseCode;
}


public static SSLSocketFactory getFactoryFromSessionCert() throws Exception {
HttpServletRequest request = getRequest();
X509Certificate certs = (X509Certificate)request.getAttribute("javax.servlet.request.X509Certificate");

KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setCertificateEntry("client_cert", certs[0]);

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, null);

SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, null);

return context.getSocketFactory();
}


I am able to retrieve the client's certificate without trouble, and can verify that it does indeed end up in keyStore. But the certificate doesn't seem to make it into keyManagerFactory.



I thought the issue was that I'm not providing a password in keyManagerFactory.init(keyStore, null), so I tried providing it but without success. And should I even have to? I understand that I would need a password if I were loading certificates and keys from a protected file, but here I'm just trying to pass along an already exposed public certificate.



As further background, this basic scheme works if I replace getFactoryFromSessionCert() with this:



public static SSLSocketFactory getFactory(File pKeyFile, String pKeyPassword) throws Exception {

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyInput = new FileInputStream(pKeyFile);
keyStore.load(keyInput, pKeyPassword.toCharArray());
keyInput.close();

keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
return context.getSocketFactory();
}


So, what am I not understanding? And how should I pass along a client certificate?







java ssl x509certificate client-certificates






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 19 at 20:41









Didjit

1881214




1881214








  • 4




    There's a lot of concepts about PKI being misused in your code. You can't use a X509Certificate without a private key to start a SSL connection, the server in the other side will never accept the handshake. If you have plans to just pass the X509 along you can set it in the header of the new request. The simple answer is... you can't reuse the mutual TLS channel in the second server because you don't have the private key to make the key exchange.
    – argoth
    Nov 19 at 21:06












  • Thanks, @argoth . I wasn't thinking of it like that, but it makes sense now. So, assuming I can make the second SSL connection with the server's own certificate, can the original client certificate be passed along to the second server in a way that satisfies client authentication? I can make your suggestion of sending it in the header work (thanks!), but what would be the proper way of solving this? I imagine it's a common need.
    – Didjit
    Nov 20 at 17:58












  • The more I think about it, the more I realize what I'm really talking about is some kind of centralized authentication. Like Kerberos, except that's overkill for my needs. I'll probably go with putting at least the essential information in the headers or a cookie, but this seems like a really bad practice in general. What would be the simplest legitimate approach?
    – Didjit
    Nov 20 at 19:41














  • 4




    There's a lot of concepts about PKI being misused in your code. You can't use a X509Certificate without a private key to start a SSL connection, the server in the other side will never accept the handshake. If you have plans to just pass the X509 along you can set it in the header of the new request. The simple answer is... you can't reuse the mutual TLS channel in the second server because you don't have the private key to make the key exchange.
    – argoth
    Nov 19 at 21:06












  • Thanks, @argoth . I wasn't thinking of it like that, but it makes sense now. So, assuming I can make the second SSL connection with the server's own certificate, can the original client certificate be passed along to the second server in a way that satisfies client authentication? I can make your suggestion of sending it in the header work (thanks!), but what would be the proper way of solving this? I imagine it's a common need.
    – Didjit
    Nov 20 at 17:58












  • The more I think about it, the more I realize what I'm really talking about is some kind of centralized authentication. Like Kerberos, except that's overkill for my needs. I'll probably go with putting at least the essential information in the headers or a cookie, but this seems like a really bad practice in general. What would be the simplest legitimate approach?
    – Didjit
    Nov 20 at 19:41








4




4




There's a lot of concepts about PKI being misused in your code. You can't use a X509Certificate without a private key to start a SSL connection, the server in the other side will never accept the handshake. If you have plans to just pass the X509 along you can set it in the header of the new request. The simple answer is... you can't reuse the mutual TLS channel in the second server because you don't have the private key to make the key exchange.
– argoth
Nov 19 at 21:06






There's a lot of concepts about PKI being misused in your code. You can't use a X509Certificate without a private key to start a SSL connection, the server in the other side will never accept the handshake. If you have plans to just pass the X509 along you can set it in the header of the new request. The simple answer is... you can't reuse the mutual TLS channel in the second server because you don't have the private key to make the key exchange.
– argoth
Nov 19 at 21:06














Thanks, @argoth . I wasn't thinking of it like that, but it makes sense now. So, assuming I can make the second SSL connection with the server's own certificate, can the original client certificate be passed along to the second server in a way that satisfies client authentication? I can make your suggestion of sending it in the header work (thanks!), but what would be the proper way of solving this? I imagine it's a common need.
– Didjit
Nov 20 at 17:58






Thanks, @argoth . I wasn't thinking of it like that, but it makes sense now. So, assuming I can make the second SSL connection with the server's own certificate, can the original client certificate be passed along to the second server in a way that satisfies client authentication? I can make your suggestion of sending it in the header work (thanks!), but what would be the proper way of solving this? I imagine it's a common need.
– Didjit
Nov 20 at 17:58














The more I think about it, the more I realize what I'm really talking about is some kind of centralized authentication. Like Kerberos, except that's overkill for my needs. I'll probably go with putting at least the essential information in the headers or a cookie, but this seems like a really bad practice in general. What would be the simplest legitimate approach?
– Didjit
Nov 20 at 19:41




The more I think about it, the more I realize what I'm really talking about is some kind of centralized authentication. Like Kerberos, except that's overkill for my needs. I'll probably go with putting at least the essential information in the headers or a cookie, but this seems like a really bad practice in general. What would be the simplest legitimate approach?
– Didjit
Nov 20 at 19:41

















active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53382331%2ftrying-to-pass-along-x509-client-certificate-to-second-server%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53382331%2ftrying-to-pass-along-x509-client-certificate-to-second-server%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

To store a contact into the json file from server.js file using a class in NodeJS

Redirect URL with Chrome Remote Debugging Android Devices

Dieringhausen