[NKP-0003]: providing https/wss endpoint for EVERY NKN node

#1

Currently NKN node only expose plain websocket/http endpoint at port 30002/30003 without ssl. But since most website are using https, it is not allowed to access any NKN node through ws/http protocol without ssl. For nkn wallet, this is kind of solvable (but not ideal) by using a few API nodes provided by us or any nodes linked with a domain and valid ssl certificate. But for nkn client, it’s very difficult to use because a client does not know in advance which node he will be connecting to. To make nkn client practically usable in most web apps, we have to make EVERY NKN node https/wss compatible.

The current code already supports wss and https, but the major reason that people don’t do it is because ssl certificate. By design, ssl certificate should be assigned to domain rather than IP address (see some discussion at https://stackoverflow.com/questions/2043617/is-it-possible-to-have-ssl-certificate-for-ip-address-not-domain-name), not to mention the tedious process of creating certificate and renew on expire.

Https itself is a centralized design, and the easiest way I can think of to make it work for every node is to use the help of another centralized system. What I’m proposing is to set up a site, e.g. x.com, and it’s doing 2 things:

  1. Making request to x.com/A.B.C.D or x.com/A-B-C-D from IP address A.B.C.D will give you a ssl certificate valid for A-B-C-D.ipv4.x.com
  2. DNS query to A-B-C-D.ipv4.x.com will get A.B.C.D as result

Then each NKN node, when starting, will get or update the ssl certificate for domain A-B-C-D.ipv4.x.com assuming his ip address is A.B.C.D, and serve https/wss endpoint at A-B-C-D.ipv4.x.com and separate port (e.g. 30004/30005) which is configurable.

Generating a unique certificate for each subdomain corresponding to an IP address may not be feasible, so I was thinking may we could just provide a single wildcard certificate that is valid for *.ipv4.x.com, but we need to be very careful here because it means the data is essentially not encrypted (since anyone can get the private key), which is OK in NKN because we are assuming every node could be malicious and can no sensitive data should be send to NKN node without encryption and signature.

Although this is a centralized solution that relies on x.com, we can make it an open protocol such that any domain (e.g. yyy.com) that implements the 2 functions above can serve this purpose, and user can choose whether to use x.com or yyy.com such that there is really no single entity that can take control.

To be more general, this could be a quite general solution for any permission-less and (real) decentralized system that has a problem in ssl certificate.

It’d be good if we can discuss about the security, feasibility, or other aspect of the proposal, or even better if we can come up with a better solution.

#2

There is ACME protocol which automates getting SSL certificate for domain: https://letsencrypt.org/docs/client-options/
Every node can generate unique id (maybe using combination of public key and IP or public key and some user-specified id) and register SSL for that domain. That way each node will exclusively own their SSL certificate’s private key (and certificate generation will be kinda more decentralized that way).

Then we only need to provide centralized DNS server (could be open source), where any node could register it’s domain for SSL certificate.
We can also ask node to sign something with it’s private key for it to be able to register itself in DNS to guarantee that some domain name was registered exactly by that node (and not some other node).

#3

If I remember correctly, ACME requires http challenge (basically statically hosted file with given content/code) which is a problem, because it requires nodes to have access to port 80.
We might be able to get the challenge to different subdomain (acme.A-B-C-D.ipv4.xxx.com) and this would actually point to xxx.com which would be able to handle the :80 http request. However, there would have to be some url like xxx.com/setChallenge/A-B-C-D/:data so the node can set what this “master” should respond to challenge.

#4

there’s also dns challenge, which requires you to set TXT record. basically you still need some kind of set challenge command on dns server, but no need for xxx.com to handle :80.

#5

After thinking about it more I like suggested wildcard solution better (since everything is e2e already we don’t care about someone owning SSL’s private key). Though I suggest to simplify it a bit more.

We can just bundle SSL’s private key together with the node and have xxx.com as default in config for parent domain parameter.
Also we should extend NodeData with node’s hostname (that will be given to clients through getwsaddr). Basically this new field in NodeData is just ip+specified parent domain (like 127-0-0-1.xxx.com).
If node operator doesn’t like xxx.com for some reason he can generate it’s own certificate for *.yyy.com and specifiy yyy.com in config instead.

The only simple thing we need to provide is open-sourced dns server which will return ip contained in the resolved hostname, e.g. 127.0.0.1 for 127-0-0-1.what.ever

What are your thoughts? @yilun @JohnSmith

#6

Let’s encrypt is what we are using now, but it has really strict limits and restrictions (e.g. 50 certificates per domain per week, see more at https://letsencrypt.org/docs/rate-limits/ ) which makes it not quite feasible to obtain a certificate for each IP (subdomain).

Actually I’m not aware of any service that can give us such high number of certificate fully automatically with a affordable price :joy: That’s why I now think wildcard solution is probably the only practical solution so far…