Repository navigation
feat(server): check box certificates - #536
Conversation
|
So in short just for my understanding. A box is still identified by its mac, but now it's additionally checked that the boxes certificate matches the pinned one (first contact original tonies cert or teddycloud cert). So if some bad guy knows the Mac and creates a fake cert it will reject? |
|
Yes, exactly. The MAC from the certificate's common name still decides which box it is. On top of that, the certificate itself now has to be the right one:
So someone who knows the MAC and builds their own certificate gets a different fingerprint, which counts as a mismatch: 401 on the box port, "not authorized" on MQTT (with core.boxCertAuth, which is on by default). Copying the real certificate doesn't help either: the TLS handshake One gap remains: if no client.der is uploaded and an attacker connects with that MAC before the real box does, the attacker's certificate gets pinned. The real box is then refused and shows up as "mismatch" in the log and the web UI. Resetting the pin |
1aa84c2 to
d7477a6
Compare
|
Could you please rebase again / merge as needed? |
d7477a6 to
9d2a109
Compare
|
Rebased onto develop again (after #545). |
Until now any client certificate whose common name looked like a box was accepted. Now: - Certificates issued by a TeddyCloud CA (TB1, TB2) are trusted. - Original Boxine certificates cannot be checked against a CA (the box only sends its own certificate, issued by "Boxine Factory SubCA nn", which is not available). If the original client.der of the box is uploaded, the box has to present exactly that certificate; without it, the first certificate a known box presents is pinned in toniebox.certPin (also with core.allowNewBox off, so nobody is locked out by the update). A box with a trusted certificate is pinned too, so no self-made certificate takes its place later. - core.boxCertAuth (default on) refuses boxes whose certificate does not match; off, they are only logged. - Result per box in internal.boxCertStatus and internal.boxCertSha256. - Same check for the MQTT server; a refused box gets CONNACK "not authorized". An unknown box id only counts as a box there while core.allowNewBox is on. The issuer check and the box id from the certificate subject are in box_cert.c, the check in box_cert_check.c. The TLS context keeps the SHA-256 fingerprint of the box certificate. Refs toniebox-reverse-engineering#85
The global setting raced with the box overlay (401 instead of 200 in about 1 of 8 runs). Setting it on the overlay of the box is reliable (0 of 26 runs failed).
9d2a109 to
0c3b72d
Compare
8291cda
into
toniebox-reverse-engineering:develop
Builds on #534 (its commit is included here until that one is merged).
Until now the box port accepted any client certificate whose common name looked like a box. Now:
certificate can take its place later.
Factory SubCA nn", which is not available). So they are checked against the real client certificate: if the
original
client.derof the box is uploaded, the box has to present exactly that certificate (also when anotherone was pinned before); without it, the first certificate a known box presents is pinned in
toniebox.certPin,also with
core.allowNewBoxoff, so nobody is locked out by the update.allowNewBoxstill decides about unknownboxes.
core.boxCertAuth(default on) refuses boxes whose certificate does not match; off, they are onlylogged.
internal.boxCertStatus(trusted / pinned / mismatch) andinternal.boxCertSha256; a pin isreset with
/api/settings/reset/toniebox.certPin?overlay=<box>.box there while
allowNewBoxis on (before, the MQTT server created an overlay for any box id).Issuer check and box id from the certificate subject in
box_cert.c(C tests), the check inbox_cert_check.c;the TLS context keeps the SHA-256 fingerprint of the box certificate.
Tests:
test_box_cert_check.py(trusted, pinned on first contact, mismatch refused, only logged withoutboxCertAuth, pin reset, known box pinned with allowNewBox off, uploaded client.der wins over an earlier pin, a box
with a TeddyCloud certificate refuses a self-made one).
Device-tested with the original firmware of a CC3200 box (3.1.0 BF2, 3.3.0, 3.4.0: pinned on first contact,
refused with a wrong pin) and an ESP32 box (v5.237.0: pinned, the same certificate as the client.der extracted
from its flash).
Refs #85