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

Add S2 keys support to zwave_js config #2157

Merged
merged 19 commits into from Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
81 changes: 64 additions & 17 deletions zwave_js/DOCS.md
Expand Up @@ -22,12 +22,12 @@ change if other devices are added to the system.
the device name in quotes: e.g., something like
`"/dev/serial/by-id/usb-0658_0200-if00"`,
`"/dev/ttyUSB0"`, `"/dev/ttyAMA0"`, or `"/dev/ttyACM0"`.
2. Set your 16-byte (32 character hex) network key in the form `2232666D1...`
used in order to connect securely to compatible devices. It is recommended
that a network key is configured as some security enabled devices (locks, etc)
2. Set your 16-byte (32 character hex) security keys in the form `2232666D1...`
in order to connect securely to compatible devices. It is recommended
that all four network keys are configured as some security enabled devices (locks, etc)
may not function correctly if they are not added securely.
* As a note, it is not recommended to securely connect *all* devices unless
necessary as it triples the amount of messages sent on the mesh.
* As a note, it is not recommended to securely connect *all* devices unless they support S2 security
as the S0 security triples the amount of messages sent on the mesh.
3. Click on "SAVE" to save the add-on configuration.
4. Start the add-on.
5. Add the Z-Wave JS integration to Home Assistant, see documentation:
Expand All @@ -40,7 +40,10 @@ Add-on configuration:

```yaml
device: /dev/ttyUSB0
network_key: 2232666D100F795E5BB17F0A1BB7A146
s0_legacy_key: 2232666D100F795E5BB17F0A1BB7A146
s2_access_control_key: A97D2A51A6D4022998BEFC7B5DAE8EA1
s2_authenticated_key: 309D4AAEF63EFD85967D76ECA014D1DF
s2_unauthenticated_key: CF338FE0CB99549F7C0EA96308E5A403
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
```

### Option `device`
Expand All @@ -59,16 +62,20 @@ In most cases this looks like one of the following:
- `"/dev/ttyAMA0"`
- `"/dev/ttyACM0"`

### Option `network_key`
### Security Keys

Security Z-Wave devices require a network key before being added to the network.
You must set the `network_key` configuration option to use a network key before
adding these devices.
There are four different security keys required to take full advantage of the
different inclusion methods that Z-Wave JS supports: `s0_legacy_key`,
`s2_access_control_key`, `s2_authenticated_key`, and `s2_unauthenticated_key`.

If you don't add a network key, it will autogenerate one for you.
If you are coming from a previous version of `zwave-js`, you likely have a key
stored in the `network_key` configuration option. When the addon is first
started, the key will be migrated from `network_key` to `s0_legacy_key` which
will ensure that your S0 secured devices will continue to function.

To generate a network key manually, you can use the following script in, e.g.,
the SSH add-on:
If any of these keys are missing on startup, the addon will autogenerate one for
you. To generate a network key manually, you can use the following script in,
e.g., the SSH add-on:

```bash
hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random
Expand All @@ -78,10 +85,43 @@ You can also use sites like this one to generate the required data:

<https://www.random.org/cgi-bin/randbyte?nbytes=16&format=h>

Ensure you keep a backup of this key. If you have to rebuild your system and
don't have a backup of this key, you won't be able to reconnect to any securely
included devices. This may mean you have to do a factory reset on those devices
and your controller, before rebuilding your Z-Wave network.
Ensure you keep a backup of these keys. If you have to rebuild your system and
don't have a backup of these keys, you won't be able to communicate to any
securely included devices. This may mean you have to do a factory reset on
those devices and your controller, before rebuilding your Z-Wave network.

> NOTE: Sharing keys between multiple security classes is a security risk, so
> if you choose to configure these keys on your own, be sure to make them
> unique!

#### Option `s0_legacy_key`

S0 Security Z-Wave devices require a network key before being added to the network.
This configuration option is required, but if it is unset the addon will generate
a new one automatically on startup.

#### Option `s2_access_control_key`

The `s2_access_control_key` must be provided in order to include devices with the
S2 Access Control security class. This security class is needed by devices such
as door locks and garage door openers. This configuration option is required,
but if it is unset the addon will generate a new one automatically on startup.

#### Option `s2_authenticated_key`

The `s2_authenticated_key` must be provided in order to include devices with
the S2 Authenticated security class. Devices such as security systems, sensors,
lighting, etc. can request this security class. This configuration option is
required, but if it is unset the addon will generate a new one automatically
on startup.

### Option `s2_unauthenticated_key`

The `s2_unauthenticated_key` must be provided in order to include devices with
the S2 Unauthenticated security class. This is similar to S2 Authenticated, but
without verification that the correct device was included. This configuration
option is required, but if it is unset the addon will generate a new one
automatically on startup.

### Option `log_level` (optional)

Expand All @@ -102,6 +142,13 @@ the Supervisor.
If you don't have a USB stick, you can use a fake stick for testing purposes.
It will not be able to control any real devices.

### Option `network_key` (deprecated)

In previous versions of the addon, this was the only key that was needed. With
the introduction of S2 security inclusion in zwave-js, this option has been
deprecated in favor of `s0_legacy_key`. If still set, the `network_key` value will be
migrated to `s0_legacy_key` on first startup.

## Known issues and limitations

- Your hardware needs to be compatible with the Z-Wave JS library
Expand Down
13 changes: 10 additions & 3 deletions zwave_js/config.json
Expand Up @@ -18,14 +18,21 @@
"discovery": ["zwave_js"],
"options": {
"device": null,
"network_key": "",
"s0_legacy_key": "",
"s2_access_control_key": "",
"s2_authenticated_key": "",
"s2_unauthenticated_key": "",
"log_level": "info"
},
"schema": {
"device": "device(subsystem=tty)",
"network_key": "match(|[0-9a-fA-F]{32,32})",
"s0_legacy_key": "match(|[0-9a-fA-F]{32,32})?",
"s2_access_control_key": "match(|[0-9a-fA-F]{32,32})?",
"s2_authenticated_key": "match(|[0-9a-fA-F]{32,32})?",
"s2_unauthenticated_key": "match(|[0-9a-fA-F]{32,32})?",
"log_level": "list(silly|debug|verbose|http|info|warn|error)?",
"emulate_hardware": "bool?"
"emulate_hardware": "bool?",
"network_key": "match(|[0-9a-fA-F]{32,32})?"
},
"image": "homeassistant/{arch}-addon-zwave_js"
}
97 changes: 72 additions & 25 deletions zwave_js/rootfs/etc/cont-init.d/config.sh
Expand Up @@ -4,32 +4,76 @@
# ==============================================================================
declare network_key

readonly DOCS_EXAMPLE_KEY="2232666D100F795E5BB17F0A1BB7A146"

if [[ "${DOCS_EXAMPLE_KEY}" == "$(bashio::config 'network_key')" ]]; then
bashio::log.fatal
bashio::log.fatal 'The add-on detected that the Z-Wave network key used'
bashio::log.fatal 'is from the documented example.'
bashio::log.fatal
bashio::log.fatal 'Using this key is insecure, because it is publicly'
bashio::log.fatal 'listed in the documentation.'
bashio::log.fatal
bashio::log.fatal 'Please check the add-on documentation on how to'
bashio::log.fatal 'create your own, secret, "network_key" and replace'
bashio::log.fatal 'the one you have configured.'
bashio::log.fatal
bashio::log.fatal 'Click on the "Documentation" tab in the Z-Wave JS'
bashio::log.fatal 'add-on panel for more information.'
bashio::log.fatal
bashio::exit.nok
elif ! bashio::config.has_value 'network_key'; then
bashio::log.info "No Network Key is set, generate one..."
network_key=$(hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random)
bashio::addon.option network_key "${network_key}"
else
network_key=$(bashio::config 'network_key')
readonly DOCS_EXAMPLE_KEY_1="2232666D100F795E5BB17F0A1BB7A146"
readonly DOCS_EXAMPLE_KEY_2="A97D2A51A6D4022998BEFC7B5DAE8EA1"
readonly DOCS_EXAMPLE_KEY_3="309D4AAEF63EFD85967D76ECA014D1DF"
readonly DOCS_EXAMPLE_KEY_4="CF338FE0CB99549F7C0EA96308E5A403"

if bashio::config.has_value 'network_key'; then
# If both 'network_key' and 's0_legacy_key' are set and keys don't match,
# we don't know which one to pick so we have to exit. If they are both set
# and do match, we will drop 'network_key'
if bashio::config.has_value 's0_legacy_key'; then
if bashio::config.equals 's0_legacy_key' "$(bashio::config \"network_key\")"; then
bashio::log.info "Both 'network_key' and 's0_legacy_key' are set and match. Dropping 'network_key' value..."
bashio::addon.option network_key
else
bashio::log.fatal "Both 'network_key' and 's0_legacy_key' are set to different values "
bashio::log.fatal "so we are unsure which one to use. One needs to be removed from the "
bashio::log.fatal "configuration in order to start the addon."
bashio::exit.nok
fi
# If we get here, 'network_key' is set and 's0_legacy_key' is not set so we need
# to migrate the key from 'network_key' to 's0_legacy_key'
else
bashio::log.info "Migrating \"network_key\" option to \"s0_legacy_key\"..."
network_key=$(bashio::string.upper "$(bashio::config 'network_key')")
bashio::addon.option s0_legacy_key "${network_key}"
bashio::addon.option network_key
bashio::log.info "Flushing config to disk due to key migration..."
bashio::addon.options > "/data/options.json"
fi
fi

# Validate that no keys are using the example from the docs and generate new random
# keys for any missing keys.
for key in "s0_legacy_key" "s2_access_control_key" "s2_authenticated_key" "s2_unauthenticated_key"; do
network_key=$(bashio::config "${key}")
if [ "${network_key}" == "${DOCS_EXAMPLE_KEY_1}" ] || [ "${network_key}" == "${DOCS_EXAMPLE_KEY_2}" ] || [ "${network_key}" == "${DOCS_EXAMPLE_KEY_3}" ] || [ "${network_key}" == "${DOCS_EXAMPLE_KEY_4}" ]; then
frenck marked this conversation as resolved.
Show resolved Hide resolved
bashio::log.fatal
bashio::log.fatal "The add-on detected that the Z-Wave network key used"
bashio::log.fatal "is from the documented example."
bashio::log.fatal
bashio::log.fatal "Using this key is insecure, because it is publicly"
bashio::log.fatal "listed in the documentation."
bashio::log.fatal
bashio::log.fatal "Please check the add-on documentation on how to"
bashio::log.fatal "create your own, secret, \"${key}\" and replace"
bashio::log.fatal "the one you have configured."
bashio::log.fatal
bashio::log.fatal "Click on the \"Documentation\" tab in the Z-Wave JS"
bashio::log.fatal "add-on panel for more information."
bashio::log.fatal
bashio::exit.nok
elif ! bashio::var.has_value "${network_key}"; then
bashio::log.info "No ${key} is set, generating one..."
bashio::addon.option ${key} "$(hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random)"
flush_to_disk=1
fi
done

# If flush_to_disk is set, it means we have generated new key(s) and they need to get
# flushed to disk
if [[ ${flush_to_disk:+x} ]]; then
bashio::log.info "Flushing config to disk due to creation of new key(s)..."
bashio::addon.options > "/data/options.json"
fi

s0_legacy=$(bashio::config "s0_legacy_key")
s2_access_control=$(bashio::config "s2_access_control_key")
s2_authenticated=$(bashio::config "s2_authenticated_key")
s2_unauthenticated=$(bashio::config "s2_unauthenticated_key")

if ! bashio::config.has_value 'log_level'; then
log_level=$(bashio::info.logging)
bashio::log.info "No log level specified, falling back to Supervisor"
Expand All @@ -41,7 +85,10 @@ fi

# Generate config
bashio::var.json \
network_key "${network_key}" \
s0_legacy "${s0_legacy}" \
s2_access_control "${s2_access_control}" \
s2_authenticated "${s2_authenticated}" \
s2_unauthenticated "${s2_unauthenticated}" \
log_level "${log_level}" \
| tempio \
-template /usr/share/tempio/zwave_config.conf \
Expand Down
7 changes: 6 additions & 1 deletion zwave_js/rootfs/usr/share/tempio/zwave_config.conf
Expand Up @@ -8,5 +8,10 @@
"cacheDir": "/data/cache",
"throttle": "slow"
},
"networkKey": "{{ .network_key }}"
"securityKeys": {
"S0_Legacy": "{{ .s0_legacy }}",
"S2_AccessControl": "{{ .s2_access_control }}",
"S2_Authenticated": "{{ .s2_authenticated }}",
"S2_Unauthenticated": "{{ .s2_unauthenticated }}"
}
}