0

I need to send the certificate along with a private key to an API endpoint. I can't do it using PKCS12 as they only accept PEM and DER format. Is there a way to send them using HttpsUrlConnection? For example, in curl this would be curl -k -X POST --key private.key --cert certificate.pem --url.

I am kinda new to all of this, so I am wondering if I should really send them in every request or should these be installed on the server and they'll be automatically sent when the API requests them.

For now, I have this snippet:

   URL url = new URL("endpoint");
   HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
   connection.setRequestMethod("POST");
   connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
   connection.setDoOutput(true);

EDIT: This question shouldn't be closed because Innovationchef provided a really good explanation of mutual TLS that is not explained in the other similar question.

DjangoDev1
  • 232
  • 4
  • 14

1 Answers1

2

Private keys are never sent. Since you are owning a private key, I will assume we are talking about mutual TLS here.

In this case, both parties have there private keys with them and it is called private because you neve share it with anyone.

Public keys are exchanged between you and your api server.

  1. Now, all you need to do is setup a SSLContext object by passing your private key and the server's public key.
  2. Provide this object while creating the connection object.
  3. Then Java will create a secured socket object for you and the TLS handshake will happen. Everything is taken care by the libraries and java ecosystem and you don't have to worry about how the certificates are exchanged.

Once the handshake is done, a connection is established and the payloads that you are sending will be encrypted.

I would suggest you add a -v switch to your curl and see the whole process happening on the bash command line. Java does the same things but with the SSLContext object.

Look at the first diagram on this link - https://docs.oracle.com/cd/E19226-01/820-7627/bncbs/index.html

When you run your curl in verbose mode, you will see all these steps being printed in the exact same order. SSLContext is a way of expressing --key private.key --cert certificate.pem in java.

Innovationchef
  • 338
  • 2
  • 10
  • 1
    1. You will need a private key if the connection is mutual SSL, else, having their public key is sufficient. 2. If you are working in a corporate environment, all the certificates are signed by a central team with company's CA(certificate authority) and hence the public key is available to everyone and they will not ask you to upload it. 3. I did not say that you "don't" need to set the certificate in SSLContext. In fact you need to. Java HttpUriConnection and SSLContext objects are just ways of translating your curl to a high level programming language java. – Innovationchef Feb 24 '21 at 19:14
  • 1
    4. Every library and framework for rest client has their own way of setting these things up - okHttp, Apache Http Client etc. Hence I am not posting a code but the theory. To understand what exactly happens behind the scene, do watch this video - https://youtu.be/oRZoeDRACrY – Innovationchef Feb 24 '21 at 19:14
  • Thanks for the explanation. I have one more question, if the private key is not sent out in the curl command, is it needed to verify the signature of the certificate? And all of this is done in the back when using the SSLContext class? You also mentioned that i need the server's public key which I think I don't have? Is this the certificate I own, because I previously uploaded it on their portal. – DjangoDev1 Feb 24 '21 at 19:14
  • 1
    They must have provided their public key somewhere. You should ask them for it. If you have their public key you will not need to put the `-k` or `--insecure` in the curl. The `-k` in curl translates to TrustStrategy ALLOW_ALL_HOSTNAME configuration in java – Innovationchef Feb 24 '21 at 19:20
  • I might have explained that wrong. I generated a private key as well as a certificate request and the server then generated a certificate. So, I now need to send the certificate in SSLContext and with that I'll prove that I actually own the certificate? – DjangoDev1 Feb 24 '21 at 20:10
  • So basically, I generate a private/public key pair for myself and send it to them in the Certificate request and they then create a certificate, using their private key and send it to me. I'm now lost as why do I need to send their certificate in the curl command along with my private key? What does this prove and how is this used for authentication? – DjangoDev1 Feb 24 '21 at 20:17
  • 1
    I am rephrasing your sentences. Please correct me if my understanding is different - "I generated a private key as well as a certificate request and the server then generated a certificate." -->> "I generated a private key and a certificate signing request(CSR) and the server signed my CSR which I later added it to my private key." Is this what you are trying to say? – Innovationchef Feb 24 '21 at 20:18
  • 1
    "So, I now need to send put the certificate in SSLContext and with that I'll prove that I actually own the certificate ?" -> So, I now need to "put" the "private" certificate in SSLContext and with that I'll prove that I actually "am a verified client to the rest service provider"? Note that the private key is not sent. Please go through the you tube video I suggested to better understand how the handshake happens and how the data is exchanged between the certificate on a verified connection is established. – Innovationchef Feb 24 '21 at 20:19
  • Yes, that is what I mean. Sorry. I actually watched the whole video but I'm stil unclear of some aspects. To sum everything, I provide my public and private key in the curl command, so that I can sign the request with my private key and the API can confirm that it is trully me. The public API key is basically the way that I confirm that I can trust the API and can confirm that the messages are from the API. Is this correct? Also, why does the server need to sign my CSR? – DjangoDev1 Feb 24 '21 at 20:19
  • 1
    Your understanding is correct. When we talk about one-way SSL, any client can make a request to the server. Sometimes, servers don't want to expose their APIs publicly for everyone to use. They only want intended clients to access their apis. So, servers signing the CSR of a client is a way to tell the client that I will trust all the payloads coming from you because I have signed your CSR and you are adding it to your private key which is being used while establishing a trusted connection. In other words, because you are in a mutual TLS agreement with your server, CSR signing is required. – Innovationchef Feb 24 '21 at 20:30
  • Thank you very much. I'll have to read up more about this though. – DjangoDev1 Feb 24 '21 at 20:31
  • Nit: `curl -k/--insecure` doesn't only allow any hostname but _all_ cert errors including unknown CA, expired, invalid usage/constraints, etc; it is equivalent to the "know-nothing" TrustManager sometimes posted. Also, TrustStrategy is only in Apache HttpClient (and things based on it); for all_hostnames in HttpsURLConnection you need a dummy HostNameVerifier or IINM EndpointIdentification in SSLParameters (since 7). Also instead of explicit SSLContext you can use sysprops to set keystore in the default context. – dave_thompson_085 Feb 24 '21 at 22:08
  • If -k allows all hostnames, why do I have to attach the certificate in the curl command? `curl.exe --insecure --key private.key --location --request POST` doesn't work and I get `400 No required SSL certificate was sent`. – DjangoDev1 Feb 25 '21 at 11:05