This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

security bug: multiple access to .pem file passed to --key-file option

nrfutill accesses (opens and closes) the .pem file passed to --key-file multiple times.

This forces the .pem file to be written to disk, which is a security breach when running on an untrusted machine (e.g. a CI platform).

For example, generating a DFU settings page with this command:

nrfutil settings generate \
    --family NRF52 \
    --application my_app_nrf52832_xxAA_s132_7.0.1.hex \
    --application-version 1 --bootloader-version 1 --bl-settings-version 2 \
    --app-boot-validation VALIDATE_ECDSA_P256_SHA256 \
    --sd-boot-validation VALIDATE_ECDSA_P256_SHA256 \
    --softdevice nRF5_SDK_16.0.0_98a08e2/components/softdevice/s132/hex/s132_nrf52_7.0.1_softdevice.hex \
    --key-file key.pem \
    settings.hex

... requires reading from 'key.pem' which must be written to disk.

We can use 'cat' to simulate a process which will perform some authentication and output the private key itself (without writing it to disk): `--key-file <(cat key.pem)`

Unfortunately, this breaks:

  File "/Users/siriobalmelli/.nix-profile/lib/python3.7/site-packages/nordicsemi/__main__.py", line 396, in generate
    sd_boot_validation_type=sd_boot_validation, sd_file=softdevice, key_file=key_file)
  File "/Users/siriobalmelli/.nix-profile/lib/python3.7/site-packages/nordicsemi/dfu/bl_dfu_sett.py", line 260, in generate
    self.sd_boot_validation_bytes = Package.sign_firmware(key_file, self.sd_bin)
  File "/Users/siriobalmelli/.nix-profile/lib/python3.7/site-packages/nordicsemi/dfu/package.py", line 581, in sign_firmware
    signer.load_key(key)
  File "/Users/siriobalmelli/.nix-profile/lib/python3.7/site-packages/nordicsemi/dfu/signing.py", line 88, in load_key
    self.sk = SigningKey.from_pem(sk_pem)
  File "/Users/siriobalmelli/.nix-profile/lib/python3.7/site-packages/ecdsa/keys.py", line 791, in from_pem
    privkey_pem = string[string.index(b("-----BEGIN EC PRIVATE KEY-----")):]
ValueError: subsection not found

This is because the file is accessed twice, first here:

            elif app_boot_validation_type == 'VALIDATE_ECDSA_P256_SHA256':
                self.app_boot_validation_type = 3 & 0xffffffff
                self.app_boot_validation_bytes = Package.sign_firmware(key_file, self.app_bin)

... and then also here:

            elif sd_boot_validation_type == 'VALIDATE_ECDSA_P256_SHA256':
                self.sd_boot_validation_type = 3 & 0xffffffff
                self.sd_boot_validation_bytes = Package.sign_firmware(key_file, self.sd_bin)

Removing softdevice validation with `--sd-boot-validation VALIDATE_GENERATED_CRC`, the problem goes away because the "keyfile" (in this case the `<(cat key.pem)` subshell) is only accessed once.

This forces the caller to write the private key file to disk. Creating a temp file is still insecure: it cannot be unlinked from the filesystem because it will be accessed twice.

Opening a file multiple times like this is also inefficient and bad form.

The private key file should be opened and read _once_, and then the contents passed to functions that require it.

I am willing to file a pull request if there is interest in getting this fixed.

Related