520 lines
24 KiB
Text
520 lines
24 KiB
Text
menu "Bootloader config"
|
|
choice LOG_BOOTLOADER_LEVEL
|
|
bool "Bootloader log verbosity"
|
|
default LOG_BOOTLOADER_LEVEL_INFO
|
|
help
|
|
Specify how much output to see in bootloader logs.
|
|
|
|
config LOG_BOOTLOADER_LEVEL_NONE
|
|
bool "No output"
|
|
config LOG_BOOTLOADER_LEVEL_ERROR
|
|
bool "Error"
|
|
config LOG_BOOTLOADER_LEVEL_WARN
|
|
bool "Warning"
|
|
config LOG_BOOTLOADER_LEVEL_INFO
|
|
bool "Info"
|
|
config LOG_BOOTLOADER_LEVEL_DEBUG
|
|
bool "Debug"
|
|
config LOG_BOOTLOADER_LEVEL_VERBOSE
|
|
bool "Verbose"
|
|
endchoice
|
|
|
|
config LOG_BOOTLOADER_LEVEL
|
|
int
|
|
default 0 if LOG_BOOTLOADER_LEVEL_NONE
|
|
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
|
|
default 2 if LOG_BOOTLOADER_LEVEL_WARN
|
|
default 3 if LOG_BOOTLOADER_LEVEL_INFO
|
|
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
|
|
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
|
|
|
|
config BOOTLOADER_SPI_WP_PIN
|
|
int "SPI Flash WP Pin when customising pins via eFuse (read help)"
|
|
range 0 33
|
|
default 7
|
|
depends on FLASHMODE_QIO || FLASHMODE_QOUT
|
|
help
|
|
This value is ignored unless flash mode is set to QIO or QOUT *and* the SPI flash pins have been
|
|
overriden by setting the eFuses SPI_PAD_CONFIG_xxx.
|
|
|
|
When this is the case, the eFuse config only defines 3 of the 4 Quad I/O data pins. The WP pin (aka ESP32
|
|
pin "SD_DATA_3" or SPI flash pin "IO2") is not specified in eFuse. That pin number is compiled into the
|
|
bootloader instead.
|
|
|
|
The default value (GPIO 7) is correct for WP pin on ESP32-D2WD integrated flash.
|
|
|
|
choice BOOTLOADER_VDDSDIO_BOOST
|
|
bool "VDDSDIO LDO voltage"
|
|
default BOOTLOADER_VDDSDIO_BOOST_1_9V
|
|
help
|
|
If this option is enabled, and VDDSDIO LDO is set to 1.8V (using eFuse
|
|
or MTDI bootstrapping pin), bootloader will change LDO settings to
|
|
output 1.9V instead. This helps prevent flash chip from browning out
|
|
during flash programming operations.
|
|
|
|
This option has no effect if VDDSDIO is set to 3.3V, or if the internal
|
|
VDDSDIO regulator is disabled via eFuse.
|
|
|
|
config BOOTLOADER_VDDSDIO_BOOST_1_8V
|
|
bool "1.8V"
|
|
depends on !ESPTOOLPY_FLASHFREQ_80M
|
|
config BOOTLOADER_VDDSDIO_BOOST_1_9V
|
|
bool "1.9V"
|
|
endchoice
|
|
|
|
config BOOTLOADER_FACTORY_RESET
|
|
bool "GPIO triggers factory reset"
|
|
default N
|
|
help
|
|
Allows to reset the device to factory settings:
|
|
- clear one or more data partitions;
|
|
- boot from "factory" partition.
|
|
The factory reset will occur if there is a GPIO input pulled low while device starts up.
|
|
See settings below.
|
|
|
|
config BOOTLOADER_NUM_PIN_FACTORY_RESET
|
|
int "Number of the GPIO input for factory reset"
|
|
depends on BOOTLOADER_FACTORY_RESET
|
|
range 0 39
|
|
default 4
|
|
help
|
|
The selected GPIO will be configured as an input with internal pull-up enabled.
|
|
To trigger a factory reset, this GPIO must be pulled low on reset.
|
|
Note that GPIO34-39 do not have an internal pullup and an external one must be provided.
|
|
|
|
config BOOTLOADER_OTA_DATA_ERASE
|
|
bool "Clear OTA data on factory reset (select factory partition)"
|
|
depends on BOOTLOADER_FACTORY_RESET
|
|
help
|
|
The device will boot from "factory" partition (or OTA slot 0 if no factory partition is present) after a
|
|
factory reset.
|
|
|
|
config BOOTLOADER_DATA_FACTORY_RESET
|
|
string "Comma-separated names of partitions to clear on factory reset"
|
|
depends on BOOTLOADER_FACTORY_RESET
|
|
default "nvs"
|
|
help
|
|
Allows customers to select which data partitions will be erased while factory reset.
|
|
|
|
Specify the names of partitions as a comma-delimited with optional spaces for readability. (Like this:
|
|
"nvs, phy_init, ...")
|
|
Make sure that the name specified in the partition table and here are the same.
|
|
Partitions of type "app" cannot be specified here.
|
|
|
|
config BOOTLOADER_APP_TEST
|
|
bool "GPIO triggers boot from test app partition"
|
|
default N
|
|
help
|
|
Allows to run the test app from "TEST" partition.
|
|
A boot from "test" partition will occur if there is a GPIO input pulled low while device starts up.
|
|
See settings below.
|
|
|
|
config BOOTLOADER_NUM_PIN_APP_TEST
|
|
int "Number of the GPIO input to boot TEST partition"
|
|
depends on BOOTLOADER_APP_TEST
|
|
range 0 39
|
|
default 18
|
|
help
|
|
The selected GPIO will be configured as an input with internal pull-up enabled.
|
|
To trigger a test app, this GPIO must be pulled low on reset.
|
|
After the GPIO input is deactivated and the device reboots, the old application will boot.
|
|
(factory or OTA[x]).
|
|
Note that GPIO34-39 do not have an internal pullup and an external one must be provided.
|
|
|
|
config BOOTLOADER_HOLD_TIME_GPIO
|
|
int "Hold time of GPIO for reset/test mode (seconds)"
|
|
depends on BOOTLOADER_FACTORY_RESET || BOOTLOADER_APP_TEST
|
|
default 5
|
|
help
|
|
The GPIO must be held low continuously for this period of time after reset
|
|
before a factory reset or test partition boot (as applicable) is performed.
|
|
|
|
config BOOTLOADER_WDT_ENABLE
|
|
bool "Use RTC watchdog in start code"
|
|
default y
|
|
help
|
|
Tracks the execution time of startup code.
|
|
If the execution time is exceeded, the RTC_WDT will restart system.
|
|
It is also useful to prevent a lock up in start code caused by an unstable power source.
|
|
NOTE: Tracks the execution time starts from the bootloader code - re-set timeout, while selecting the
|
|
source for slow_clk - and ends calling app_main.
|
|
Re-set timeout is needed due to WDT uses a SLOW_CLK clock source. After changing a frequency slow_clk a
|
|
time of WDT needs to re-set for new frequency.
|
|
slow_clk depends on ESP32_RTC_CLOCK_SOURCE (INTERNAL_RC or EXTERNAL_CRYSTAL).
|
|
|
|
config BOOTLOADER_WDT_DISABLE_IN_USER_CODE
|
|
bool "Allows RTC watchdog disable in user code"
|
|
depends on BOOTLOADER_WDT_ENABLE
|
|
default n
|
|
help
|
|
If it is set, the client must itself reset or disable rtc_wdt in their code (app_main()).
|
|
Otherwise rtc_wdt will be disabled before calling app_main function.
|
|
Use function rtc_wdt_feed() for resetting counter of rtc_wdt.
|
|
Use function rtc_wdt_disable() for disabling rtc_wdt.
|
|
|
|
config BOOTLOADER_WDT_TIME_MS
|
|
int "Timeout for RTC watchdog (ms)"
|
|
depends on BOOTLOADER_WDT_ENABLE
|
|
default 9000
|
|
range 0 120000
|
|
help
|
|
Verify that this parameter is correct and more then the execution time.
|
|
Pay attention to options such as reset to factory, trigger test partition and encryption on boot
|
|
- these options can increase the execution time.
|
|
Note: RTC_WDT will reset while encryption operations will be performed.
|
|
|
|
config APP_ROLLBACK_ENABLE
|
|
bool "Enable app rollback support"
|
|
default n
|
|
help
|
|
After updating the app, the bootloader runs a new app with the "ESP_OTA_IMG_PENDING_VERIFY" state set.
|
|
This state prevents the re-run of this app. After the first boot of the new app in the user code, the
|
|
function should be called to confirm the operability of the app or vice versa about its non-operability.
|
|
If the app is working, then it is marked as valid. Otherwise, it is marked as not valid and rolls back to
|
|
the previous working app. A reboot is performed, and the app is booted before the software update.
|
|
Note: If during the first boot a new app the power goes out or the WDT works, then roll back will happen.
|
|
Rollback is possible only between the apps with the same security versions.
|
|
|
|
config APP_ANTI_ROLLBACK
|
|
bool "Enable app anti-rollback support"
|
|
depends on APP_ROLLBACK_ENABLE
|
|
default n
|
|
help
|
|
This option prevents rollback to previous firmware/application image with lower security version.
|
|
|
|
config APP_SECURE_VERSION
|
|
int "eFuse secure version of app"
|
|
depends on APP_ANTI_ROLLBACK
|
|
default 0
|
|
help
|
|
The secure version is the sequence number stored in the header of each firmware.
|
|
The security version is set in the bootloader, version is recorded in the eFuse field
|
|
as the number of set ones. The allocated number of bits in the efuse field
|
|
for storing the security version is limited (see APP_SECURE_VERSION_SIZE_EFUSE_FIELD option).
|
|
|
|
Bootloader: When bootloader selects an app to boot, an app is selected that has
|
|
a security version greater or equal that recorded in eFuse field.
|
|
The app is booted with a higher (or equal) secure version.
|
|
|
|
The security version is worth increasing if in previous versions there is
|
|
a significant vulnerability and their use is not acceptable.
|
|
|
|
Your partition table should has a scheme with ota_0 + ota_1 (without factory).
|
|
|
|
config APP_SECURE_VERSION_SIZE_EFUSE_FIELD
|
|
int "Size of the efuse secure version field"
|
|
depends on APP_ANTI_ROLLBACK
|
|
range 1 32
|
|
default 32
|
|
help
|
|
The size of the efuse secure version field. Its length is limited to 32 bits.
|
|
This determines how many times the security version can be increased.
|
|
|
|
config EFUSE_SECURE_VERSION_EMULATE
|
|
bool "Emulate operations with efuse secure version(only test)"
|
|
default n
|
|
depends on APP_ANTI_ROLLBACK
|
|
help
|
|
This option allow emulate read/write operations with efuse secure version.
|
|
It allow to test anti-rollback implemention without permanent write eFuse bits.
|
|
In partition table should be exist this partition `emul_efuse, data, 5, , 0x2000`.
|
|
|
|
endmenu # Bootloader
|
|
|
|
|
|
menu "Security features"
|
|
|
|
# These three are the actual options to check in code,
|
|
# selected by the displayed options
|
|
config SECURE_SIGNED_ON_BOOT
|
|
bool
|
|
default y
|
|
depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
|
|
|
|
config SECURE_SIGNED_ON_UPDATE
|
|
bool
|
|
default y
|
|
select MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
|
depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
|
|
|
config SECURE_SIGNED_APPS
|
|
bool
|
|
default y
|
|
depends on SECURE_SIGNED_ON_BOOT || SECURE_SIGNED_ON_UPDATE
|
|
|
|
|
|
config SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
|
bool "Require signed app images"
|
|
default n
|
|
depends on !SECURE_BOOT_ENABLED
|
|
help
|
|
Require apps to be signed to verify their integrity.
|
|
|
|
This option uses the same app signature scheme as hardware secure boot, but unlike hardware secure boot it
|
|
does not prevent the bootloader from being physically updated. This means that the device can be secured
|
|
against remote network access, but not physical access. Compared to using hardware Secure Boot this option
|
|
is much simpler to implement.
|
|
|
|
config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
|
|
bool "Bootloader verifies app signatures"
|
|
default n
|
|
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
|
help
|
|
If this option is set, the bootloader will be compiled with code to verify that an app is signed before
|
|
booting it.
|
|
|
|
If hardware secure boot is enabled, this option is always enabled and cannot be disabled.
|
|
If hardware secure boot is not enabled, this option doesn't add significant security by itself so most
|
|
users will want to leave it disabled.
|
|
|
|
config SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
|
bool "Verify app signature on update"
|
|
default y
|
|
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
|
help
|
|
If this option is set, any OTA updated apps will have the signature verified before being considered valid.
|
|
|
|
When enabled, the signature is automatically checked whenever the esp_ota_ops.h APIs are used for OTA
|
|
updates, or esp_image_format.h APIs are used to verify apps.
|
|
|
|
If hardware secure boot is enabled, this option is always enabled and cannot be disabled.
|
|
If hardware secure boot is not enabled, this option still adds significant security against network-based
|
|
attackers by preventing spoofing of OTA updates.
|
|
|
|
config SECURE_BOOT_ENABLED
|
|
bool "Enable hardware secure boot in bootloader (READ DOCS FIRST)"
|
|
default n
|
|
help
|
|
Build a bootloader which enables secure boot on first boot.
|
|
|
|
Once enabled, secure boot will not boot a modified bootloader. The bootloader will only load a partition
|
|
table or boot an app if the data has a verified digital signature. There are implications for reflashing
|
|
updated apps once secure boot is enabled.
|
|
|
|
When enabling secure boot, JTAG and ROM BASIC Interpreter are permanently disabled by default.
|
|
|
|
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
|
|
|
|
choice SECURE_BOOTLOADER_MODE
|
|
bool "Secure bootloader mode"
|
|
depends on SECURE_BOOT_ENABLED
|
|
default SECURE_BOOTLOADER_ONE_TIME_FLASH
|
|
|
|
config SECURE_BOOTLOADER_ONE_TIME_FLASH
|
|
bool "One-time flash"
|
|
help
|
|
On first boot, the bootloader will generate a key which is not readable externally or by software. A
|
|
digest is generated from the bootloader image itself. This digest will be verified on each subsequent
|
|
boot.
|
|
|
|
Enabling this option means that the bootloader cannot be changed after the first time it is booted.
|
|
|
|
config SECURE_BOOTLOADER_REFLASHABLE
|
|
bool "Reflashable"
|
|
help
|
|
Generate a reusable secure bootloader key, derived (via SHA-256) from the secure boot signing key.
|
|
|
|
This allows the secure bootloader to be re-flashed by anyone with access to the secure boot signing
|
|
key.
|
|
|
|
This option is less secure than one-time flash, because a leak of the digest key from one device
|
|
allows reflashing of any device that uses it.
|
|
|
|
endchoice
|
|
|
|
config SECURE_BOOT_BUILD_SIGNED_BINARIES
|
|
bool "Sign binaries during build"
|
|
depends on SECURE_SIGNED_APPS
|
|
default y
|
|
help
|
|
Once secure boot or signed app requirement is enabled, app images are required to be signed.
|
|
|
|
If enabled (default), these binary files are signed as part of the build process. The file named in
|
|
"Secure boot private signing key" will be used to sign the image.
|
|
|
|
If disabled, unsigned app/partition data will be built. They must be signed manually using espsecure.py
|
|
(for example, on a remote signing server.)
|
|
|
|
config SECURE_BOOT_SIGNING_KEY
|
|
string "Secure boot private signing key"
|
|
depends on SECURE_BOOT_BUILD_SIGNED_BINARIES
|
|
default secure_boot_signing_key.pem
|
|
help
|
|
Path to the key file used to sign app images.
|
|
|
|
Key file is an ECDSA private key (NIST256p curve) in PEM format.
|
|
|
|
Path is evaluated relative to the project directory.
|
|
|
|
You can generate a new signing key by running the following command:
|
|
espsecure.py generate_signing_key secure_boot_signing_key.pem
|
|
|
|
See https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html for details.
|
|
|
|
config SECURE_BOOT_VERIFICATION_KEY
|
|
string "Secure boot public signature verification key"
|
|
depends on SECURE_SIGNED_APPS && !SECURE_BOOT_BUILD_SIGNED_BINARIES
|
|
default signature_verification_key.bin
|
|
help
|
|
Path to a public key file used to verify signed images. This key is compiled into the bootloader and/or
|
|
app, to verify app images.
|
|
|
|
Key file is in raw binary format, and can be extracted from a
|
|
PEM formatted private key using the espsecure.py
|
|
extract_public_key command.
|
|
|
|
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
|
|
|
|
choice SECURE_BOOTLOADER_KEY_ENCODING
|
|
bool "Hardware Key Encoding"
|
|
depends on SECURE_BOOTLOADER_REFLASHABLE
|
|
default SECURE_BOOTLOADER_NO_ENCODING
|
|
help
|
|
|
|
In reflashable secure bootloader mode, a hardware key is derived from the signing key (with SHA-256) and
|
|
can be written to eFuse with espefuse.py.
|
|
|
|
Normally this is a 256-bit key, but if 3/4 Coding Scheme is used on the device then the eFuse key is
|
|
truncated to 192 bits.
|
|
|
|
This configuration item doesn't change any firmware code, it only changes the size of key binary which is
|
|
generated at build time.
|
|
|
|
config SECURE_BOOTLOADER_KEY_ENCODING_256BIT
|
|
bool "No encoding (256 bit key)"
|
|
|
|
config SECURE_BOOTLOADER_KEY_ENCODING_192BIT
|
|
bool "3/4 encoding (192 bit key)"
|
|
|
|
endchoice
|
|
|
|
config SECURE_BOOT_INSECURE
|
|
bool "Allow potentially insecure options"
|
|
depends on SECURE_BOOT_ENABLED
|
|
default N
|
|
help
|
|
You can disable some of the default protections offered by secure boot, in order to enable testing or a
|
|
custom combination of security features.
|
|
|
|
Only enable these options if you are very sure.
|
|
|
|
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
|
|
|
|
config FLASH_ENCRYPTION_ENABLED
|
|
bool "Enable flash encryption on boot (READ DOCS FIRST)"
|
|
default N
|
|
help
|
|
If this option is set, flash contents will be encrypted by the bootloader on first boot.
|
|
|
|
Note: After first boot, the system will be permanently encrypted. Re-flashing an encrypted
|
|
system is complicated and not always possible.
|
|
|
|
Read https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html before enabling.
|
|
|
|
config FLASH_ENCRYPTION_INSECURE
|
|
bool "Allow potentially insecure options"
|
|
depends on FLASH_ENCRYPTION_ENABLED
|
|
default N
|
|
help
|
|
You can disable some of the default protections offered by flash encryption, in order to enable testing or
|
|
a custom combination of security features.
|
|
|
|
Only enable these options if you are very sure.
|
|
|
|
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html and
|
|
https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html for details.
|
|
|
|
menu "Potentially insecure options"
|
|
visible if FLASH_ENCRYPTION_INSECURE || SECURE_BOOT_INSECURE
|
|
|
|
# NOTE: Options in this menu NEED to have SECURE_BOOT_INSECURE
|
|
# and/or FLASH_ENCRYPTION_INSECURE in "depends on", as the menu
|
|
# itself doesn't enable/disable its children (if it's not set,
|
|
# it's possible for the insecure menu to be disabled but the insecure option
|
|
# to remain on which is very bad.)
|
|
|
|
config SECURE_BOOT_ALLOW_ROM_BASIC
|
|
bool "Leave ROM BASIC Interpreter available on reset"
|
|
depends on SECURE_BOOT_INSECURE || FLASH_ENCRYPTION_INSECURE
|
|
default N
|
|
help
|
|
By default, the BASIC ROM Console starts on reset if no valid bootloader is
|
|
read from the flash.
|
|
|
|
When either flash encryption or secure boot are enabled, the default is to
|
|
disable this BASIC fallback mode permanently via eFuse.
|
|
|
|
If this option is set, this eFuse is not burned and the BASIC ROM Console may
|
|
remain accessible. Only set this option in testing environments.
|
|
|
|
config SECURE_BOOT_ALLOW_JTAG
|
|
bool "Allow JTAG Debugging"
|
|
depends on SECURE_BOOT_INSECURE || FLASH_ENCRYPTION_INSECURE
|
|
default N
|
|
help
|
|
If not set (default), the bootloader will permanently disable JTAG (across entire chip) on first boot
|
|
when either secure boot or flash encryption is enabled.
|
|
|
|
Setting this option leaves JTAG on for debugging, which negates all protections of flash encryption
|
|
and some of the protections of secure boot.
|
|
|
|
Only set this option in testing environments.
|
|
|
|
config SECURE_BOOT_ALLOW_SHORT_APP_PARTITION
|
|
bool "Allow app partition length not 64KB aligned"
|
|
depends on SECURE_BOOT_INSECURE
|
|
help
|
|
If not set (default), app partition size must be a multiple of 64KB. App images are padded to 64KB
|
|
length, and the bootloader checks any trailing bytes after the signature (before the next 64KB
|
|
boundary) have not been written. This is because flash cache maps entire 64KB pages into the address
|
|
space. This prevents an attacker from appending unverified data after the app image in the flash,
|
|
causing it to be mapped into the address space.
|
|
|
|
Setting this option allows the app partition length to be unaligned, and disables padding of the app
|
|
image to this length. It is generally not recommended to set this option, unless you have a legacy
|
|
partitioning scheme which doesn't support 64KB aligned partition lengths.
|
|
|
|
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT
|
|
bool "Leave UART bootloader encryption enabled"
|
|
depends on FLASH_ENCRYPTION_INSECURE
|
|
default N
|
|
help
|
|
If not set (default), the bootloader will permanently disable UART bootloader encryption access on
|
|
first boot. If set, the UART bootloader will still be able to access hardware encryption.
|
|
|
|
It is recommended to only set this option in testing environments.
|
|
|
|
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_DECRYPT
|
|
bool "Leave UART bootloader decryption enabled"
|
|
depends on FLASH_ENCRYPTION_INSECURE
|
|
default N
|
|
help
|
|
If not set (default), the bootloader will permanently disable UART bootloader decryption access on
|
|
first boot. If set, the UART bootloader will still be able to access hardware decryption.
|
|
|
|
Only set this option in testing environments. Setting this option allows complete bypass of flash
|
|
encryption.
|
|
|
|
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_CACHE
|
|
bool "Leave UART bootloader flash cache enabled"
|
|
depends on FLASH_ENCRYPTION_INSECURE
|
|
default N
|
|
help
|
|
If not set (default), the bootloader will permanently disable UART bootloader flash cache access on
|
|
first boot. If set, the UART bootloader will still be able to access the flash cache.
|
|
|
|
Only set this option in testing environments.
|
|
|
|
config SECURE_BOOT_TEST_MODE
|
|
bool "Secure boot test mode: don't permanently set any eFuses"
|
|
depends on SECURE_BOOT_INSECURE
|
|
default N
|
|
help
|
|
If this option is set, all permanent secure boot changes (via eFuse) are disabled.
|
|
|
|
Log output will state changes which would be applied, but they will not be.
|
|
|
|
This option is for testing purposes only - it completely disables secure boot protection.
|
|
|
|
endmenu # Potentially Insecure
|
|
endmenu # Security features
|