Moddable-OpenSource / moddable

Tools for developers to create truly open IoT products using standard JavaScript on low cost microcontrollers.
http://www.moddable.com
1.33k stars 235 forks source link

SecureSocket does not validate the name against the CN/SAN of the certificate #1421

Open cmidgley opened 2 weeks ago

cmidgley commented 2 weeks ago

Build environment: Windows Moddable SDK version: 5.0.1 Target device: ESP32, Simulator (Win)

Description A SecureSocket connection can be made to a server even when the connection name does not match the certificate names (CN/SAN). The connection succeeds and communicates without errors over the secure connection.

Steps to Reproduce

  1. Start with examples/network/socket/socketsecure
  2. Change the connection line to use the IP address of example.com (93.184.215.14 as of this write-up), which does not match the certificate. Alternatively, you can set up a DNS entry that resolves to that address and then use the DNS name instead of the IP address.

Line before changing:

(new SecureSocket({host, port,

Line after changing:

(new SecureSocket({host: "93.184.215.14", port,

This approach keeps the host variable referencing www.example.com so the HTTP GET will use the expected hostname (example.com requires this to return the normal page content, though it can be overridden and the connection will succeed but the HTTP payload will be an error message).

  1. Run on simulator or ESP32 and see that the connection succeeds and the page content is returned.

Other information If the certificate is expired (or time is not set on ESP32; can't easily simulate on win as Time.set(...) isn't supported), or the certificate root is invalid, it correctly rejects the session.

phoddie commented 2 weeks ago

You're going to make me go back and relearn how this is supposed to work. ;) Will take a look but understand that TLS matters are seldom quick to resolve.

cmidgley commented 2 weeks ago

As I'm sure you recognize, it's an attack vector since there is no validation that the domain name matches the certificate, but it doesn't affect the actual communications. While likely best to be implemented in SecureSocket, another approach might be to have an API where the callered can get the (decoded?) certificate info and leave it up to the caller to do the check.

I did some research on the requirements, in case it might help. There are two fields that contain the domain info:

Certificate:
    Data:
        Subject: CN = some.domain.com
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:some.domain.com, DNS:another.domain.com, DNS:*.wild.domain.com

The Subject: CN = ... field will represent the "primary" domain (and is considered legacy), whereas the Subject Alternate Name (SAN) will contain multiple names for each domain that is registered. Both support wildcards, where the wildcard *.domain.com will match example.domain.com but not match domain.com. If the SAN is provided, the CN field can be ignored.

Also worth noting, an alternate format instead of commas on the DNS entry is to list each entry on a separate line. It is not valid for it to be both comma and separate lines:

Certificate:
    Data:
        Subject: CN = some.domain.com
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:some.domain.com
                DNS:another.domain.com
                DNS:*.wild.domain.com

Let me know if I can help further. This is not a high priority for me (lots of time before my code reaches the public) - but it is an attack vector that seems worth addressing eventually.

phoddie commented 1 week ago

@cmidgley – yes, I understood that this is a potential vulnerability. As such, it should be solved in the TLS stack to benefit all clients.