how to use two separate SSL certs when my app calls different endpoints?

hey guys. i have a spring application. there are two endpoints that are being called in it (for example endpoint1 and endpoint2). and also there are two security certificates (for example cretificate1 for endpoint1 and certificate2 for endpoint2). i have a problem. how to switch between certificates? because once the application is running, the JKS is already loaded. how to approach this issue? thanks in advance.
55 Replies
JavaBot
JavaBot7mo ago
This post has been reserved for your question.
Hey @bambyzas! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
Peter Rader
Peter Rader7mo ago
A jks can contain multiple certificates. You could put both certificates into the one keystore and the Endpoints will decide what certificate to use by themselves.
JavaBot
JavaBot7mo ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
bambyzas
bambyzasOP7mo ago
really? i had an idea about being able to load both certificates into the keystore and reference the one i need at any given time with an alias shouldnt i be using SSL bundles?
Peter Rader
Peter Rader7mo ago
Have you installed the KeyStore Explorer? It is a very nice tool.
bambyzas
bambyzasOP7mo ago
sure, i have it i have set up my jks with two certs long time ago so this part is done but i dont know what to do next
Peter Rader
Peter Rader7mo ago
Start the app and try to use the endpoints. Are there any exceptions?
bambyzas
bambyzasOP7mo ago
app starts fine but wait there for a minute. how is Spring gonna decide which certificate to use for which endpoint? i just want to understand
Peter Rader
Peter Rader7mo ago
Is it a incomming connection to your app? Is it a outgoing connection from your app?
bambyzas
bambyzasOP7mo ago
um, idk tbh. my app is running, and then it will be making calls to the 3rd party endpoints. so as i understand its outgoing connection
Peter Rader
Peter Rader7mo ago
ok, then it is an outgoing connection from your app. Well we have 3 phases. 1. Handshake 2. Certificate check 3. Key Exchange. Here is a good tutorial: https://youtu.be/j9QmMEWmcfo?t=194 In stage 3 the keys decide what certificates are used for data-transfer. In phase 1 the TLS asks what chiphres should be used, what encoding algorithm should be used and what blocksize should be used for data-transfer and key-interchange. In phase 2 the endpoint guarantees to your app that he is authentic. In phase 3 your app send the signatures of all certificates your app knows, the endpoint then report what signature matches best, then your app use the according certificate. Then you have a TLS session (aka ssl-session). btw: in the video your app is the "client" and the endpoint is the "server".
bambyzas
bambyzasOP7mo ago
In phase 3 your app send the signatures of all certificates your app knows, the endpoint then report what signature matches best, then your app use the according certificate. okay, but if i have completely different endpoints with different hosts? like facebook.com/endpoint1 and google.com/endpoint2?
imp_o_rt
imp_o_rt7mo ago
when you init a tls handshake with the target, it presents a certificate java will check all trustedCertEntrys in the keystore you supply to find one that matches you don't have to specify which cert to use for which endpoint because if there is any matching trusted in the truststore you supply it will automatically be selected
bambyzas
bambyzasOP7mo ago
but there are two completely separate targets with separate hostnames. how does the target know which cert to choose? it will just blindly check trustedCertEntry?
imp_o_rt
imp_o_rt7mo ago
not blindly; it will look for a cert that matches what is presented by the server example from google.com (with javax.net.debug=all): server presents:
javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 12:55:17.321 BST|CertificateMessage.java:1172|Consuming server Certificate handshake message (
"Certificate": {
[snip]
{
"certificate" : {
"version" : "v3",
"serial number" : "0203BC53596B34C718F5015066",
"signature algorithm": "SHA256withRSA",
"issuer" : "CN=GTS Root R1, O=Google Trust Services LLC, C=US",
"not before" : "2020-08-13 01:00:42.000 BST",
"not after" : "2027-09-30 01:00:42.000 BST",
"subject" : "CN=GTS CA 1C3, O=Google Trust Services LLC, C=US",
"subject public key" : "RSA",
"extensions" : [
javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 12:55:17.321 BST|CertificateMessage.java:1172|Consuming server Certificate handshake message (
"Certificate": {
[snip]
{
"certificate" : {
"version" : "v3",
"serial number" : "0203BC53596B34C718F5015066",
"signature algorithm": "SHA256withRSA",
"issuer" : "CN=GTS Root R1, O=Google Trust Services LLC, C=US",
"not before" : "2020-08-13 01:00:42.000 BST",
"not after" : "2027-09-30 01:00:42.000 BST",
"subject" : "CN=GTS CA 1C3, O=Google Trust Services LLC, C=US",
"subject public key" : "RSA",
"extensions" : [
client finds a match:

javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 12:55:17.387 BST|X509TrustManagerImpl.java:301|Found trusted certificate (
"certificate" : {
"version" : "v3",
"serial number" : "0203E5936F31B01349886BA217",
"signature algorithm": "SHA384withRSA",
"issuer" : "CN=GTS Root R1, O=Google Trust Services LLC, C=US",
"not before" : "2016-06-22 01:00:00.000 BST",
"not after" : "2036-06-22 01:00:00.000 BST",
"subject" : "CN=GTS Root R1, O=Google Trust Services LLC, C=US",
"subject public key" : "RSA",
"extensions" : [
{
ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true

javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 12:55:17.387 BST|X509TrustManagerImpl.java:301|Found trusted certificate (
"certificate" : {
"version" : "v3",
"serial number" : "0203E5936F31B01349886BA217",
"signature algorithm": "SHA384withRSA",
"issuer" : "CN=GTS Root R1, O=Google Trust Services LLC, C=US",
"not before" : "2016-06-22 01:00:00.000 BST",
"not after" : "2036-06-22 01:00:00.000 BST",
"subject" : "CN=GTS Root R1, O=Google Trust Services LLC, C=US",
"subject public key" : "RSA",
"extensions" : [
{
ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
bambyzas
bambyzasOP7mo ago
wait. so i can just dump all my certs into one jks, and i can just call two completely different apis and everything will be fine?
imp_o_rt
imp_o_rt7mo ago
this is how java works with all other certs with a magical massive jks called cacerts check $JAVA_HOME/lib/security/cacerts - it's a jks which has hundreds of trusted cert entries, mine has 139 for example
bambyzas
bambyzasOP7mo ago
😦
No description
imp_o_rt
imp_o_rt7mo ago
this is windows so for you it would be %JAVA_HOME% but only if you've configured that as an env var wherever you have java installed look in lib/security/cacerts
bambyzas
bambyzasOP7mo ago
i dont have such env var
imp_o_rt
imp_o_rt7mo ago
it doesn't matter i was just highlighting how all other "well known" certs are handled in java
bambyzas
bambyzasOP7mo ago
can you explain this? i dont understand how to read it and why is it a match like u said?
imp_o_rt
imp_o_rt7mo ago
1. server says "here is my cert chain" 2. client says "i recognise this chain of certs" hence can be trusted
bambyzas
bambyzasOP7mo ago
and why is it a match like u said?
imp_o_rt
imp_o_rt7mo ago
because the signatures match between the cert presented by server and one stored by client (in this case in cacerts)
bambyzas
bambyzasOP7mo ago
but you are sending one certificate here
imp_o_rt
imp_o_rt7mo ago
google is sending a chain of certs (one signed by the other all the way up to a self-signed root CA) - i can't show all here because of discord limit
bambyzas
bambyzasOP7mo ago
ok
imp_o_rt
imp_o_rt7mo ago
my client is recognising a part of the chain (i don't need to trust the whole chain) all the way up to the same root CA, with the same signatures if i trust your signer i don't need to explicitly trust you
bambyzas
bambyzasOP7mo ago
but here i cant see trustedCertEntry field that u mentioned
imp_o_rt
imp_o_rt7mo ago
that's from the output of keytool, unrelated to this debug stuff but it's loading those trusted cert entries from the jdk's cacerts
bambyzas
bambyzasOP7mo ago
but wait. java app isnt sending jks its sending one cert to the api
imp_o_rt
imp_o_rt7mo ago
you're now describing mTLS (mutual TLS) where the client sends a cert
bambyzas
bambyzasOP7mo ago
um, yes
imp_o_rt
imp_o_rt7mo ago
ok so that's the keystore not the trust store
bambyzas
bambyzasOP7mo ago
yes. i never said such thing as trust store
imp_o_rt
imp_o_rt7mo ago
in the mTLS case, after the stuff i mentioned relating to trust, the server sends a request to the client called a CertificateRequest which says "you must present a certificate satisfying these requirements"
bambyzas
bambyzasOP7mo ago
yes
imp_o_rt
imp_o_rt7mo ago
but similar to the trust store java looks into its configured keystore to find a key that matches the certificate request so you can have multiple private key entries in the same keystore and java will select the right one depending on the CertificateRequest it received from the server
bambyzas
bambyzasOP7mo ago
oh, now it makes sense
imp_o_rt
imp_o_rt7mo ago
here's an example of a CertificateRequest (from https://certauth.cryptomix.com/json/ ):
"CertificateRequest": {
"certificate_request_context": "",
"extensions": [
"signature_algorithms (13)": {
"signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp521r1_sha512, ed25519, ed448, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, ecdsa_sha224, rsa_sha224]
}
]
}
"CertificateRequest": {
"certificate_request_context": "",
"extensions": [
"signature_algorithms (13)": {
"signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp521r1_sha512, ed25519, ed448, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, ecdsa_sha224, rsa_sha224]
}
]
}
in this simple case the only requirement is to send a client cert signed using one of the signature schemes in the list, but in real life the CertificateRequest asks for a cert signed by a specific CA with a specific signature in this case i didn't present a cert:

javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 13:20:13.532 BST|CertificateMessage.java:1106|No available client authentication scheme
javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 13:20:13.532 BST|CertificateMessage.java:1140|Produced client Certificate message (
"Certificate": {
"certificate_request_context": "",
"certificate_list": [
]
}
)
javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 13:20:13.532 BST|CertificateVerify.java:1093|No X.509 credentials negotiated for CertificateVerify

javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 13:20:13.532 BST|CertificateMessage.java:1106|No available client authentication scheme
javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 13:20:13.532 BST|CertificateMessage.java:1140|Produced client Certificate message (
"Certificate": {
"certificate_request_context": "",
"certificate_list": [
]
}
)
javax.net.ssl|DEBUG|B1|HttpClient-1-Worker-0|2024-06-19 13:20:13.532 BST|CertificateVerify.java:1093|No X.509 credentials negotiated for CertificateVerify
usually this leads the server to hang up on you but in this testing server's case it accepts it anyway and returns a 403
bambyzas
bambyzasOP7mo ago
okay. but what would happen if my api provider changes root cert?
imp_o_rt
imp_o_rt7mo ago
if you mean the root cert that it uses in its CertificateRequest, then you have to get a new cert signed by that new CA and update the keystore
bambyzas
bambyzasOP7mo ago
no, i mean root certificate in general you know, companies sometimes change their root certs. thats what i meant
imp_o_rt
imp_o_rt7mo ago
companies change their edge certs all the time but this doesn't affect your setup since they will be signed by the same small handful of root certs and that signer/root cert chain is unchanged changing the root cert is usually a once-in-a-decade major exercise but also if that root cert is a well known one e.g. verisign/GTS/ISRG/etc then updating the jdk will update the cacerts
bambyzas
bambyzasOP7mo ago
current root cert is CN DigiCert Global Root CA. but soon it will be changed to digicert global g2 tls rsa sha256 2020 ca1. so the signer (like u said) will not remain unchanged
imp_o_rt
imp_o_rt7mo ago
but will you have a new cert to identify with? if the signer changes you need a new client cert (and therefore need to update your keystore)
bambyzas
bambyzasOP7mo ago
idk if signer changes. as i understand it remains the same DigiCert Globalb?
imp_o_rt
imp_o_rt7mo ago
if signer changes then old cert signed by old signer will no longer be valid unless if only server side is changing but client CertificateRequest (mTLS) doesn't
bambyzas
bambyzasOP7mo ago
can you provide me some info/resources on that? bc i tried googling and couldnt find any info 😦
Unknown User
Unknown User7mo ago
Message Not Public
Sign In & Join Server To View
bambyzas
bambyzasOP7mo ago
hi
Unknown User
Unknown User7mo ago
Message Not Public
Sign In & Join Server To View
Peter Rader
Peter Rader7mo ago
I was bizzy but I see @imp_o_rt took it just right. Thanks.
JavaBot
JavaBot7mo ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.

Did you find this page helpful?