Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENHANCED: HTTP Unix daemon now supports multiple certificates. #76

Closed
wants to merge 2 commits into from
Closed

ENHANCED: HTTP Unix daemon now supports multiple certificates. #76

wants to merge 2 commits into from

Conversation

triska
Copy link
Member

@triska triska commented Dec 19, 2016

Simply supply several --certfile and --keyfile options. Their relative
order must be identical, for example cert1, cert2, ..., key1, key2, or
cert1, key1, cert2, key2, ... etc.

Thus, you can host dual-stack RSA/ECDSA HTTPS servers, for example.

Simply supply several --certfile and --keyfile options. Their relative
order must be identical, for example cert1, cert2, ..., key1, key2, or
cert1, key1, cert2, key2, ... etc.

Thus, you can host dual-stack RSA/ECDSA HTTPS servers, for example.
This default was undocumented and, more importantly, prevented running
a server that relies entirely on SNI to present certificates.

No longer requiring a mandatory certificate/key pair to be specified
allows you to automatically distinguish clients that support SNI: If
you omit --certfile, clients that do not support SNI are rejected.
@JanWielemaker
Copy link
Member

I'm not very happy using the default certificate. It allows me to do (SWISH does this) swipl daemon.pl --https without anything else. The http_certificate_hook/3 hook will create a self-signed certificate if needed, so I can have a secure SWISH without any configuration. I'd like to have that back. Why can't we have a default if nothing was specified by the user? If there is a good reason for that, can we have a hook that gets back the old behaviour?

Second, the pairs of key and cert file options seems very delicate to me. If they do not match you get simply false. As you also need pairs in the interface, doesn't it make more sense to also have pairs in the options? For example --cert=<certfile>:<keyfile>[:<passwordfile>]

P.s., I never like findall as a way to extract from structures. Why all the copying? It is both slow and, although safe in this case, easily leads to semantic issues. What about this?

?- include([Key]>>functor(Key, key, 1), [aap(x), key(1), key(2), noot(y)], X).
X = [key(1), key(2)].

@triska
Copy link
Member Author

triska commented Dec 20, 2016

I am addressing the comments in the order you raised them:

I'm not very happy using the default certificate.

(I suppose you mean "I am very happy using the default certificate", otherwise the rest does not make sense.)

It allows me to do (SWISH does this) swipl daemon.pl --https without anything else.

Please note that this is not sufficient even today, since it uses potentially weak ciphers, putting the integrity and privacy of your users' data at risk. For better security, you could use for example:

swipl daemon.pl --https --cipherlist='EECDH+AESGCM:EDH+AESGCM:EECDH+AES256:EDH+AES256'

To this, you would then simply append the "default" certificate and key, obtaining:

swipl daemon.pl --https --cipherlist='EECDH+AESGCM:EDH+AESGCM:EECDH+AES256:EDH+AES256' \
                        --keyfile=https/server.key --certfile=https/server.crt

Obviously, it makes sense to put this in a shell script, so that you do not have to type this every time.

The main point here is that running a secure HTTPS server is, already now, not that convenient on the command line, and as you see from the above, even the combination of certificate and key file is shorter than specifying a commonly used cipher suite with acceptable security.

The http_certificate_hook/3 hook will create a self-signed certificate if needed, so I can have a secure SWISH without any configuration.

The http_certificate_hook/3 runs exactly like before also if you merge this pull request. You only need to add the --keyfile and --certfile options to the SWISH invocation. Regarding the "secure SWISH without any configuration", please see above: You will have to at least modify the default ciphers to make it secure.

I'd like to have that back.

No problem, simply add an unofficial --swish flag to the Unix daemon, much in the same way the defaults are currently silently used. Better yet, let us generalize your specific use case and consider adding an official (or even unofficial) flag like --https-suite that implements all of the following:

  • implies --https
  • redirects from HTTP to HTTPS.
  • uses a well-defined default certificate and key file, unless otherwise specified
  • uses secure ciphers, unless otherwise specified.

You may find a better name for this flag. Maybe --https-defaults?

Why can't we have a default if nothing was specified by the user?

This is the most important point: We should not have a default, because "no certificate at all" is a perfectly valid use case for an HTTPS server that supports SNI. I want to give users the ability to easily (= with the daemon) run an HTTPS server that relies solely on SNI to present the certificates, and drops the connection if clients do not support SNI.

Moreover, I think silently exposing files (as is currently the case) is the worst of all possible options. If the default is official, then at least it should be clearly stated that the daemon does this. However (to repeat) it should not do this at all, because we should be able to run a server without default certificates.

Regarding the specific implementation, I agree with what you wrote: Specifying triples like this would be a nice solution, also allowing for different passwords per key! And yes, the silent failure can be easily turned into an exception.

@JanWielemaker
Copy link
Member

This is the most important point: We should not have a default, because "no certificate at all" is a perfectly valid use case for an HTTPS server that supports SNI. I want to give users the ability to easily (= with the daemon) run an HTTPS server that relies solely on SNI to present the certificates, and drops the connection if clients do not support SNI.

That is interesting. One of the issues I'm struggling with for a long time is that one often needs an HTTP server inside a LAN that needs some form of security (e.g., plain HTTP and basic authentication
is really open), but the HTTPS route is very involved. As it is inside a LAN you cannot use
LetsEncrypt!, so you are bound to self-signed certificates. Does SNI allow for a better route?

Otherwise, your arguments lead me to think that we need hooks. That allows an application to specify sensible defaults or load the configuration from a file, etc. Which hooks is the second question. One option is to have a hook that allows managing the option list. That is simple and flexible, but the disadvantage is that you need to understand the passed options. The alternative is to have hooks for the several tasks. What do you think?

This brings me to a somewhat related issue: once upon a time http_unix_daemon.pl was intended to deal with the Unix daemon infrastructure and little else. There is now quite complicated logic for dealing with server starting and certificates. Does it make sense to split that? I'm not really convinced whether splitting or not makes it better.

@triska
Copy link
Member Author

triska commented Dec 21, 2016

Since there are now many simultaneous issues being raised, I would like to factor out the configuration discussion, for which I have filed #77.

Regarding the "HTTPS inside a LAN", my input is: You only need control over a single host that is accessible from the web to obtain many certificates from Let's Encrypt. For example, with control over swi-prolog.org, you could get certificates for:

  • machine1.swi-prolog.org
  • machine2.swi-prolog.org
  • etc.

You can deploy these certificates to the machines inside your LAN, and then resolve access to machine1.swi-prolog.org for machines that are inside your LAN internally, by letting the configuration of these machines point to the local environment.

Using SNI allows you to supply a server name that can be different from the host name of the machine. The above works even without SNI, but SNI could help if you want to call your internal machines differently.

Note also that the SNI name is transmitted (of course) before a secure connection has been established. In other words, the SNI name is transmitted in plain text, and therefore exposes the host name that the client used for establishing the connection! This is definitely not wanted in some cases, since it potentially tells an adversary details about your network configuration. Consequently, there should also be an option to disable SNI for the client, and I will likely add that.

@triska
Copy link
Member Author

triska commented Dec 27, 2016

I am closing this because it is subsumed by the new hook proposed in #77.

We only need to apply #80 to make the certificate and key optional. Any further certificates, including sensible defaults, can be added with the new ssl_add_certificate_key/3.

@triska triska closed this Dec 27, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants