2

Is there any way that we can configure an Nginx without a public certificate?

The objective here is, I want to publish an API on public internet, but all the API client (whitelisted clients) should SSL-pinning the public certificate within their Apps, instead of getting the certificate adhoc per request. So we don't need the nginx to publish the public certificate.

I understand that public certificate is harmless to be shared publicly, but this peculiar request is coming from our corporate client's. They even asked whether we can put an invalid public certificate in the nginx... so when an "attacker" that do not have the real public certificate will see the API as an error, while genuine ssl-pinned clients will be able to use the API normally.

3
  • 2
    Note that pinning certificates comes with a lot of overhead, as you need to plan how you are going to distribute updated certificates, including in the case when then original certificate was compromised and can no longer be used. You would be a lot better off having your own CA (properly secured) and distributing the CA root cert to your clients, so they can trust any cert signed by your CA. However properly securing a CA (usually involves have intermediates) is a big task by itself (though properly securing a single cert is harder). But as the answers say, client certs are probably better.
    – jcaron
    Jan 24 at 10:34
  • 2
    What exactly do you mean by "the nginx to publish the public certificate"?
    – Bergi
    Jan 24 at 13:13
  • Which type of clients are we talking about here?
    – Bergi
    Jan 24 at 13:13

4 Answers 4

13

Your question (and justification) for the question as asked don't really make much sense technically. I can make some statements which I hope may be helpful to you -

  1. To configure NGinx without a public certificate you would use HTTP (ie abandon encryption). HTTPS is designed around public/private encryption so it would not make sense for Nginx to not use this.

  2. It is possible for you to create a self signed certificate, and for users to "pin" that. You could also create your own CA with a self signed CA certificate so you could issue multiple certs.

  3. Your corporate clients don't know how much they don't know. An attacker would simply accept the invalid certificate and continue. A certificate encrypts the session between browser and server - it does not prevent a browser from accessing the content if it does not have a public cert, nor does it mean the server can trust the client.

  4. If you want to increase security, look into client side certificates. This is almost the reverse of the kind of cert you are talking about. In effect, you run your own CA, and sign public keys - and then require those keys be used when a client is communicating with you (and this is supported by most browsers, but is non-trivial to get your mind around deploying - it is quite practical though) This basically validates the clients to the server. If the clients are all communicating through an API - this this is not common practice with API's should tell you something though - why not just use a regular HTTPS cert and then a shared secret?

8
  • "session between browser and cert" does not exist or even make sense, and server cert is involved in keyexchange and thus encryption only with the ancient and now rare 'RSA' keyexchange in TLS1.2 down only. Proper (mainstream) browsers impede or prevent access to a site with a bad cert or no cert, but hacked browsers or other clients can indeed accesss the site (and its content) anyway. Jan 24 at 8:14
  • @dave_thompson_085 cert should have read server. Also my regular cgrome and furefix browsers had no problem dealing with a self signed cert I made yesterday (after appropriate warnings).
    – davidgo
    Jan 24 at 9:09
  • look into client side certificates Been there, done that - and that can be a major can of worms. Client certs imply secure key distribution if you really care about security, which is almost impossible to implement if you have non-technical users. Nevermind all the time you're going to have to spend supporting users with client issues if you use client certs, given most of them won't even be able to spell TLS. Jan 24 at 10:21
  • 1
    @AndrewHenle The OP is talking about some sort of API exposed to dedicated client. This use case benefits immensely from mTLS, but indeed requires a substantial technical expertise to put in place. The client in such setups is expected to manage its own cert by contacting a dedicated client certification authority endpoint subject to rules and policies.
    – oakad
    Jan 24 at 11:01
  • 1
    @oakad No need to contact the CA - it just needs a CA cert added to its cert store. Having implemented this for a business many years ago rolling out client side certs is quite practical in a controlled environment.
    – davidgo
    Jan 24 at 16:33
10

... but all the API client (whitelisted clients) should SSL-pinning the public certificate within their Apps, instead of getting the certificate adhoc per request. So we don't need the nginx to publish the public certificate.

It is not possible to do certificate based server authentication without the server providing the certificate. This includes pinning of certificates in the client - which requires the server to send the certificate too in order to verify it against the pinned certificate.

It is possible to let nginx use a self-signed certificate or a certificate issued by a private CA. There is nothing special about it, just configure this certificate. When clients only check if a specific certificate is served then it is possible that this self-signed certificate does not contain any real information like subject etc, it does need to contain the public key though matching the private key.

They even asked whether we can put an invalid public certificate in the nginx... so when an "attacker" that do not have the real public certificate will see the API as an error, while genuine ssl-pinned clients will be able to use the API normally.

It is not possible to serve one certificate to some clients (the good ones) and a different one to other clients (the bad ones) unless the clients can be distinguished before the certificate is send inside the TLS handshake. Such distinction could be done solely based on TCP based information like source IP address. Or clients could use some hidden non-public domain name in the SNI (i.e. different from one used in DNS lookup) which matches a different configuration in nginx.

3
  • Actually the certificate selection process has access to a bit more than just source IP, it also could use anything in the client hello message, like SNI does. So depending on how custom the client and server can go, it could be possible to either use special SNI values (it does not need to match the actual HTTP host) or add extra options in the client hello.
    – jcaron
    Jan 24 at 10:25
  • 1
    @jcaron: Good point, the "good" client could simple use some "hidden" domain name in the SNI which is not visible on the public internet (i.e. different SNI than domain used for DNS lookup) and thus get a different certificate. I've incorporated that idea in my answer. Jan 24 at 11:26
  • (@jcaron) although until TLS1.3+ESNI/ECH is (widely-enough) supported, attacker can sniff SNI from a legitimate client and use that -- if they don't just ignore the bad cert Jan 26 at 13:20
1

The objective here is, I want to publish an API on public internet, but all the API client (whitelisted clients) should SSL-pinning the public certificate within their Apps, instead of getting the certificate adhoc per request. So we don't need the nginx to publish the public certificate.

The server's certificate isn't actually involved in setting up the TLS encryption in the first place. Its only purpose is to verify the connection that has been set up – TLS could indeed work without certificates, and that would not stop the attacker from establishing the connection at all. So the plan would not work; it's technically achievable but quite useless.

(It might be the case that your client is remembering how ancient SSL and TLS versions worked; it used to be a somewhat common thing to use the certificate's RSA key directly as part of the TLS key exchange; but that's not how it has worked for many years. TLSv1.3 doesn't even have the option anymore.)

They even asked whether we can put an invalid public certificate in the nginx... so when an "attacker" that do not have the real public certificate will see the API as an error, while genuine ssl-pinned clients will be able to use the API normally.

That's also completely useless for reasons explained above. The attacker doesn't need the certificate in the first place – a bad certificate is something that can be merely ignored by the TLS client.

(In fact, you could remind the client that they probably have done so themselves, when they visited a website with an expired certificate and clicked "Ignore certificate"... While that's not really the same thing – the certificate in that case was technically valid – your client probably won't be able to tell the difference, so it might still get the point across.)


There are two valid options you can use instead:

  • Use client certificates, also known as "mTLS" – a very common choice for restricted-access APIs. This would require each API client to have its own certificate that it sends to the server, and which is verified by the server (by the client using its own private key to provide proof). Tell your client that this is what actual banks use for their payment APIs.

  • Use PSK authentication, which is a valid option in TLSv1.3 and doesn't use certificates at all. (I think it might have been a valid option in TLSv1.2 as well, but AFAIK there were changes in TLSv1.3 that made PSK much more viable in that version.) With this mode, both the client and the server share what looks a lot like a username and password (the 'PSK identity' and the PSK itself), but unlike regular passwords the PSK is actually involved in establishing encryption – without providing a valid PSK it's impossible to make the TLS connection.

1
  • 4
    Although deprecated, RSA keyexchange still exists in 1.2 down and is sometimes used. 1.2 down allows anonymous (no server auth) DH or ECDH (though useless for goal of this Q); 1.3 does not. All protocols support PSK (though 1.3 does so differently) and OpenSSL implements it, but it requires a specific API nginx doesn't support. 1.3 uses the PSK mechanism for resumption, instead of reusing the master secret, and this makes the mechanism very common, but preconfiguration is still very rare. Jan 24 at 8:14
-1

Disclaimer: IF my answer works, it involves breaking standard TLS. I would only work with a custom HTTP client.

Without discussing the merit of your approach (other answers have done that), I am wondering if... Could you not "simply" provide a different certificate, one of which the public key is not the one matching your private key. There might be mechanism that will prevent nginx from working if you attempt to do so. And you would have to make sure on your client that you can set the HTTP stack to completely ignore the certificate sent by the server and use your built-in one instead.

I don't have a very in-depth knowledge of TLS, but I "imagine" the encryption key that's negotiated to encrypt the traffic (for instance using ECDH) will be negotiated using the public key from the server, public key that is (I believe) contained in the certificate.

So a client establishing an encrypted channel using the public key in the certificate sent by your server would fail, as the private key on your server wouldn't match the public key in the certificate.

2
  • " I "imagine" the encryption key that's negotiated to encrypt the traffic (for instance using ECDH) will be negotiated using the public key from the server, public key that is (I believe) contained in the certificate" - what you describe is RSA key exchange (not ECDH), which is considered obsolete and no longer available in TLS 1.3. With modern crypto the certificate is only used for authenticating the peer and not involved in key exchange. Jan 24 at 15:12
  • Yes the stack used by nginx (OpenSSL) will refuse to serve a cert that doesn't match the (static authentication) privatekey -- and I believe most or all others will too, either directly or by using keystores which prevent it. But in any case the keys used for [FF]DHE or ECDHE are ephemeral, not in the cert or keystore, and generated and transmitted separately, almost always without any application control, so the legit client couldn't know what key to use even if it had a completely custom TLS stack. Jan 26 at 13:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .