Certificates for hosts on private networks

I’ve got a native app (it runs on Linux/OSX/Windows) that serves webpages to smartphones on the local network. Users run the app, then point their phone’s browser at the app’s server. For example: http://192.168.1.10 The phones now interact with the app through the server it’s running.

The web pages served to the phone benefit greatly from fullscreen, device orientation, and device motion features but those features are planned to require HTTPS only.

The app is intended to be installed by average users not technical users (think mom, dad, sister, brother) so installing certificates manually is a non-starter and installing anything whatsoever on the phone is also a non-starter. Asking users to set up custom DNS or configure their routers is also a non-starter.

So, the question is is it possible to enable HTTPS (local server on lan serving to local machines on same lan) in such a scenario and can Let’s Encrypt help with that?

Note: there is an rendezvous server so users don’t have to type ip addresses but that’s mostly irrelevant. Once the rendezvous server has directed the phones to the local server running the app all communication is on the local network between the app and the phones.

If you’re curious the app is here.

2 Likes

No I don’t think it’s possible. Regardless what CA you choose.

At first LE will not issue certs for IP addresses, see Certificate for Static IP.

Secondly it’s would not be possible to issue a cert for a local IP, because everyone could issue a cert for it’s own local IP. So everyone could get a cert and go to your network and intercept all HTTPS connections.
Additionally it’s not possible for a CA to prove you control a local server behind an IP. How could a CA access this server?

The only way to provide HTTPS for local IPs is to use self-singed certs, which will of course trigger error warnings.

Someone suggested that I run a DNS server and generate domains on the fly as in somesessionid.myapp.com where somesessionid.myapp.com points to the user’s localhost ip address. If I have a cert for myapp.com then maybe that would work?

Yes this should work AFAIK as you can get certs for domains.

It will work, but it will require that the service be accessible remotely in order to perform the validation. It would not be able to point to the localhost IP.

If Let’s Encrypt implements DNS based validation that would be a way to more easily implement this without requiring external connectivity, but I don’t know if they will be implementing that part of the ACME spec.

1 Like

They will allow DNS based verification:

The Let’s Encrypt CA will look at the domain name being requested and
issue one or more sets of challenges. These are different ways that
the agent can prove control of the domain. For example, the CA might
give the agent a choice of either:

Provisioning a DNS record under example.com, or
Provisioning an HTTP resource under a well-known URI on https://example.com/

https://letsencrypt.org/howitworks/technology/

@rugk: We should probably clarify the language on that page. It’s intended to list DNS provisioning as an example of what a CA “might” do. The current status is that we will launch with only the SimpleHTTP and DVSNI challenges, and most likely support DNS challenges later on.

@greggman: The problem you pose, of issuing meaningful certs for hosts on a local network, is a very hard one that is being thought about a lot, but no one has come up with a satisfactory solution. You are on the right path for one workaround, though. You can indeed set up hostnames like somesessionid.myapp.com and get certificates for them. There are a few tricky things, though:

  • A certificate for myapp.com won’t be valid for somesessionid.myapp.com. You’ll need to get a certificate issued for somesessionid.myapp.com. Also, in order to be secure, your app running on the local network should generate its own private key, and share the public key with your service to get it signed by a CA.

  • In order to be signed by a CA, somesessionid.myapp.com needs to resolve to a server accessible on the public Internet. But in order to be used by the local network app, somesessionid.myapp.com needs to resolve to a local address. You can probably work around this by making somesessionid.myapp.com temporarily point to a public web server for enrollment, and then re-point it to the local address during use. Keep in mind that certs will need periodic renewal, so you will have to account for that somehow.

1 Like

Maybe you can do something like this:

First time use of app, serves an unencrypted welcome portal, Little message about accepting what ever comes next.
After accepting, then have the app always serve encrypted.

Could even get a little creative with icons, like choose your browser, which give visuals on how to permanently accept, depending on if chrome, safari, dolphin etc. I know it would be a pain at first, but it shouldn't be to hard to get. What do you think?
--..Archer

I think you under estimate how scary and convoluted it is to “click through” on Android and I don’t think most soccer moms are not going to click through after reading how it’s unsafe

see img

It might be possible to use a proxy to complete the verification step using a temporarily-publicly-resolvable version of the DNS name that’s later changed to point to a private LAN IP address.

A security problem is that since these names don’t have an inherent independent meaning for the users, it’s not really clear what their browsers are “verifying” when they verify the certificate. Effectively, they’re always trusting the app developer not to MITM them; in some configurations they might also be trusting other users of the service not to do so, too (because the user doesn’t necessarily have a useful way to distinguish between “my instance” and “my neighbor’s instance”).

I think Let’s Encrypt might be able to issue certificates that would work out for this use case, subject to these limitations, if you can proxy the verification step with a public IP address and then update the DNS records afterward.

If it’s your own app then you can (and it would not be a bad idea) add public key pinning to it, so that it only accepts this one certificate.
However - of course - in this case you don’t need to let it sign by a CA at all, you can just use a self-generated certificate.

1 Like

That doesn't mitigate the ssl warnings you will get from not being signed by a CA

That doesn't mitigate the ssl warnings you will get from not being signed by a CA

Of course it does. If it's your own app where you can implement your own HTTPS validation you can of course skip the CA validation and use key pinning (which is much more secure).
At least on Android many apps do the first step - accidentally -, but doesn't do the second step, so their HTTPS validation is effectively broken.

If it's not your own app (like the browser) then that's of course another case, because there you the HTTPS connection is of course CA-validated.

I'm sorry but you are mistaken, by key pinning I assume you mean HPKP?
The purpose of HTTP Public Key Pinning is not to replace the CA system, it is to ensure that after connecting securely once, that any further connections are forced to accept only that legitimate CA signed certificate (with optional backups in case of compromise), even if a different malicious CA signed certificate for the same server is presented to the client.

If you really must use your own self signed certificate, the only way to avoid the SSL warnings you will get on the clients, is to install your custom certificates/certificate chain into each client's trust store.

I'm sorry but you are mistaken, by key pinning I assume you mean HPKP?

No. :smile:
If I meant this I would have written HPKP. Because HPKP is HTTP Public Key Pinning. Note the HTTP - that indicates that it's a HTTP header (at least in this case).

So no what I meant is 'normal' key pinning: You grab the public key of your cert, put it into your app and allow only HTTPS connections which use this cert. As you control the app and it's hardcoded public key it's not possible to use another cert (at least if the implementation has no flaws, of course) and you can skip the CA-check for that cert as it's neither necessary nor useful in this case.
But as I said this of course only works if you develop an app, which only connects to your own server.

@rugk Well you can excuse me, because as I quote below, the question at hand relates to HTTP and HTTPS, and CERTIFICATES, as in WEBPAGEs sent to a BROWSER, so forgive me for thinking you were talking about HPKP, you are in fact talking about something totally different than the topic at hand.

Not sure what makes you think that HPKP is not 'normal' key pinning. Please link me to info on the key pinning you speak of. When you said earlier:

I assumed you meant @greggman 's app that he runs himself on a server. That clients connect to on a web browser.

Ah, no I meant a mobile app. Sorry for the confusion.
Well… HPKP is a kind of kind pinning - I just wanted to show the difference between the app key pinning* and HPKP.
Here are more information:

And yes, you’re right he mentioned that the users use a browser. In this case that’s of course not possible.
My reply should just be a note about the general problem for others. (not especially for him) That’s why I said ‘If it’s your own app’ but it seems this was misinterpreted (because of the ‘native app’ part in the first post, which mean another kind of app). So I meant an mobile app you develop yourself.

* this is not an official name

Take a look at this: https://blog.filippo.io/how-plex-is-doing-https-for-all-its-users/

Note: I edited the thread title to reflect more clearly what the thread is about.

Thanks!

Yea that’s looks like it will work for home users on the internet.

Unfortunately my software is also used in a bunch of museums and installations. In that case there is no internet. Users connect to the WiFi, using fake DNS and Captive Portal support they either wait for the captive portal stuff to kick in and get automatically connected to the installation (iOS) OR they type any domain name like h.com and get redirected to the installation (android/winphone).

As there’s no connection to the internet I’m curious if there is a possible solution. It seems like if the browser is going to check certificates and doesn’t need to go online to do it I can include a “private” certificate directly in the app, of course that means anyone can steal it and use it for whatever they want and eventually it will probably get banned/deauthorized etc… not even sure that will work.