Initial commit
This commit is contained in:
28
docs/contributing.md
Normal file
28
docs/contributing.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# How to Contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
Contributions to this project must be accompanied by a Contributor License
|
||||
Agreement. You (or your employer) retain the copyright to your contribution;
|
||||
this simply gives us permission to use and redistribute your contributions as
|
||||
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||
your current agreements on file or to sign a new one.
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted one
|
||||
(even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult
|
||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||
information on using pull requests.
|
||||
|
||||
## Community Guidelines
|
||||
|
||||
This project follows [Google's Open Source Community
|
||||
Guidelines](https://opensource.google/conduct/).
|
||||
1
docs/img/OpenSK.svg
Normal file
1
docs/img/OpenSK.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 116.46 110.31"><defs><style>.cls-1{fill:#5f6368;}.cls-2{fill:#fff;}</style></defs><title>Mono</title><path class="cls-1" d="M42.39,47.19v0h0Z"/><path class="cls-1" d="M51.49,44.09a11.46,11.46,0,0,1-6.2,10.21.05.05,0,0,1,0,0,31.79,31.79,0,0,1-1.45-3c-.12-.29-.23-.57-.33-.83s-.17-.43-.25-.65c-.3-.84-.53-1.63-.8-2.53a3.48,3.48,0,0,0-1-5.83,3.5,3.5,0,0,0-1.3-.25,3.41,3.41,0,0,0-1.77.49,1.64,1.64,0,0,0-.22.14,2.08,2.08,0,0,0-.4.32,1.21,1.21,0,0,0-.19.2,1.12,1.12,0,0,0-.18.2,2.71,2.71,0,0,0-.24.35,1.74,1.74,0,0,0-.11.18,2.72,2.72,0,0,0-.11.25,1.75,1.75,0,0,0-.12.32,2,2,0,0,0-.09.33,3.36,3.36,0,0,0-.08.71,2.19,2.19,0,0,0,0,.36,1.26,1.26,0,0,0,0,.33v0a3,3,0,0,0,.09.32,1.75,1.75,0,0,0,.12.32,2.14,2.14,0,0,0,.1.22l.12.22a1.79,1.79,0,0,0,.2.28,1.71,1.71,0,0,0,.21.26,1.54,1.54,0,0,0,.26.25L33.67,55a12.09,12.09,0,0,1,4.51-22.24h0a5.35,5.35,0,0,1,.56-.07c.21,0,.41,0,.62-.05H40l.62,0,.51,0h.06l.54.07.27,0,.27,0a11.54,11.54,0,0,1,8.14,6.49A11.36,11.36,0,0,1,51.49,44.09Z"/><path class="cls-1" d="M42.39,47.19v0h0Z"/><path class="cls-2" d="M42.39,47.19v0h0Z"/><path class="cls-1" d="M35.27,84a8.77,8.77,0,0,1-.72,3.67,5.46,5.46,0,0,1-2.06,2.42,6.1,6.1,0,0,1-6.18,0,5.61,5.61,0,0,1-2.09-2.41,8.36,8.36,0,0,1-.74-3.6v-.8a8.65,8.65,0,0,1,.73-3.67,5.57,5.57,0,0,1,2.08-2.44,6.05,6.05,0,0,1,6.17,0,5.54,5.54,0,0,1,2.07,2.4,8.52,8.52,0,0,1,.74,3.65Zm-2.47-.74a6.2,6.2,0,0,0-.89-3.63,3.17,3.17,0,0,0-5,0A6.1,6.1,0,0,0,26,83.2V84a6.15,6.15,0,0,0,.91,3.62,2.92,2.92,0,0,0,2.54,1.28,2.89,2.89,0,0,0,2.52-1.25A6.28,6.28,0,0,0,32.8,84Z"/><path class="cls-1" d="M46.76,85.58a6.28,6.28,0,0,1-1.11,3.91,3.56,3.56,0,0,1-3,1.46,3.61,3.61,0,0,1-2.79-1.14v5H37.5V80.19h2.19l.1,1.08A3.46,3.46,0,0,1,42.63,80a3.59,3.59,0,0,1,3,1.44,6.47,6.47,0,0,1,1.1,4Zm-2.36-.2a4.4,4.4,0,0,0-.63-2.51A2.06,2.06,0,0,0,42,81.94a2.19,2.19,0,0,0-2.09,1.2v4.69A2.21,2.21,0,0,0,42,89.06a2.07,2.07,0,0,0,1.78-.91A4.93,4.93,0,0,0,44.4,85.38Z"/><path class="cls-1" d="M53.42,91a4.9,4.9,0,0,1-3.66-1.42,5.16,5.16,0,0,1-1.4-3.78v-.29A6.29,6.29,0,0,1,49,82.63a4.69,4.69,0,0,1,1.71-1.94A4.58,4.58,0,0,1,53.15,80a4.16,4.16,0,0,1,3.33,1.37,5.86,5.86,0,0,1,1.18,3.9v1H50.75a3.18,3.18,0,0,0,.88,2.07,2.61,2.61,0,0,0,1.93.76,3.21,3.21,0,0,0,2.65-1.32L57.49,89a4.31,4.31,0,0,1-1.69,1.47A5.3,5.3,0,0,1,53.42,91Zm-.28-9a2,2,0,0,0-1.58.68,3.59,3.59,0,0,0-.77,1.91h4.52v-.18a2.89,2.89,0,0,0-.63-1.8A2,2,0,0,0,53.14,81.9Z"/><path class="cls-1" d="M61.7,80.19l.07,1.22A3.79,3.79,0,0,1,64.84,80q3.3,0,3.36,3.78v7H65.83V83.91a2.19,2.19,0,0,0-.43-1.49A1.84,1.84,0,0,0,64,81.94a2.28,2.28,0,0,0-2.14,1.3v7.52H59.46V80.19Z"/><path class="cls-1" d="M78.28,87.1a1.72,1.72,0,0,0-.66-1.45,7.76,7.76,0,0,0-2.38-1,11.5,11.5,0,0,1-2.73-1.16,3.63,3.63,0,0,1-1.94-3.18A3.44,3.44,0,0,1,72,77.46a5.67,5.67,0,0,1,3.64-1.12,6.17,6.17,0,0,1,2.64.55,4.31,4.31,0,0,1,1.83,1.56,4,4,0,0,1,.66,2.24H78.28a2.21,2.21,0,0,0-.7-1.74,2.86,2.86,0,0,0-2-.63,3,3,0,0,0-1.88.51A1.73,1.73,0,0,0,73,80.28a1.56,1.56,0,0,0,.72,1.3,8.34,8.34,0,0,0,2.38,1,11,11,0,0,1,2.67,1.12,4.17,4.17,0,0,1,1.47,1.45,3.68,3.68,0,0,1,.47,1.91,3.37,3.37,0,0,1-1.36,2.82,5.92,5.92,0,0,1-3.7,1,7,7,0,0,1-2.83-.57,4.65,4.65,0,0,1-2-1.57,4,4,0,0,1-.72-2.35H72.6a2.3,2.3,0,0,0,.8,1.88,3.51,3.51,0,0,0,2.29.66,3,3,0,0,0,1.94-.52A1.7,1.7,0,0,0,78.28,87.1Z"/><path class="cls-1" d="M87,84.62l-1.61,1.7v4.44H82.92V76.54h2.47v6.67l1.37-1.69,4.16-5h3l-5.29,6.3,5.59,7.92H91.28Z"/><path class="cls-1" d="M59.74,19.62,41.21,25.14v5.48h.1a.85.85,0,0,1,.23,0l.48.06.43.07h.15l.09,0a13.53,13.53,0,0,1,9.55,7.61c.08.17.14.35.21.52H72.58a2.35,2.35,0,0,1,1.75,3.92s-5.14,6-6.82,6a2.82,2.82,0,0,1-1.91-.75l-2.68-2.47a1.21,1.21,0,0,0-1.52-.1l-4,2.8a2.77,2.77,0,0,1-1.62.52H52.6c-.11.28-.21.56-.33.83a13.37,13.37,0,0,1-5.79,6.22l-.16.15A31.31,31.31,0,0,0,59.74,67.74a31.51,31.51,0,0,0,18.13-24.3,48.25,48.25,0,0,0,.4-5.23V25.14Z"/><path class="cls-1" d="M42.39,47.19v0h0Z"/><path class="cls-1" d="M42.39,47.19v0h0Z"/><path class="cls-2" d="M42.39,47.19v0h0Z"/><path class="cls-1" d="M42.39,47.19v0h0Z"/><path class="cls-1" d="M42.39,47.19v0h0Z"/><path class="cls-2" d="M42.39,47.19v0h0Z"/><path class="cls-1" d="M42.39,47.19v0h0Z"/><path class="cls-1" d="M42.39,47.19v0h0Z"/><path class="cls-2" d="M42.39,47.19v0h0Z"/></svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
BIN
docs/img/devkit_annotated.jpg
Normal file
BIN
docs/img/devkit_annotated.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 532 KiB |
BIN
docs/img/dongle_clip.jpg
Normal file
BIN
docs/img/dongle_clip.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 172 KiB |
BIN
docs/img/dongle_front.jpg
Normal file
BIN
docs/img/dongle_front.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 400 KiB |
BIN
docs/img/dongle_pads.jpg
Normal file
BIN
docs/img/dongle_pads.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 127 KiB |
262
docs/install.md
Normal file
262
docs/install.md
Normal file
@@ -0,0 +1,262 @@
|
||||
<img alt="OpenSK logo" src="img/OpenSK.svg" width="200px">
|
||||
|
||||
# Installation guide
|
||||
|
||||
This document describes in details how to turn a Nordic nRF52840 board into a
|
||||
working FIDO2 security key.
|
||||
|
||||
## Pre-requisite
|
||||
|
||||
### Hardware
|
||||
|
||||
You will need one the following supported boards:
|
||||
|
||||
* [Nordic nRF52840-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
|
||||
development kit. This board is more convenient for development and debug
|
||||
scenarios as the JTAG probe is already on the board.
|
||||
* [Nordic nRF52840 Dongle](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
|
||||
to have a more practical form factor.
|
||||
|
||||
In the case of the Nordic USB dongle, you will also need the following extra
|
||||
hardware:
|
||||
|
||||
* a [Segger J-Link](https://www.segger.com/products/debug-probes/j-link/) JTAG
|
||||
probe.
|
||||
* a
|
||||
[TC2050 Tag-Connect programming cable](http://www.tag-connect.com/TC2050-IDC-NL-050-ALL).
|
||||
* a [Tag-Connect TC2050 ARM2010](http://www.tag-connect.com/TC2050-ARM2010)
|
||||
adaptor
|
||||
* optionally a
|
||||
[Tag-Connect TC2050 retainer clip](http://www.tag-connect.com/TC2050-CLIP)
|
||||
to keep the spring loaded connector pressed to the PCB.
|
||||
|
||||
Although [OpenOCD](http://openocd.org/) should be supported we encountered some
|
||||
issues while trying to flash a firmware with it. Therefore we suggest at the
|
||||
moment to use a
|
||||
[Segger J-Link](https://www.segger.com/products/debug-probes/j-link/) probe
|
||||
instead.
|
||||
|
||||
This guide **does not** cover how to setup the JTAG probe on your system.
|
||||
|
||||
### Software
|
||||
|
||||
In order to compile and flash a working OpenSK firmware, you will need the
|
||||
following:
|
||||
|
||||
* a working [Rust](https://rustup.rs/) toolchain installed on your system
|
||||
* python3 and pip
|
||||
* the OpenSSL command line tool
|
||||
|
||||
The scripts provided in this project have been tested under Linux and OS X. We
|
||||
haven't tested them on Windows and other platforms.
|
||||
|
||||
## Compiling the firmware
|
||||
|
||||
### Initial setup
|
||||
|
||||
If you just cloned this repository, you need to run the following script
|
||||
(_output may differ_):
|
||||
|
||||
```shell
|
||||
$ ./setup.sh
|
||||
[-] Applying patch "01-persistent-storage.patch"... DONE.
|
||||
[-] Applying patch "02-usb.patch"... DONE.
|
||||
[-] Applying patch "03-app-memory.patch"... DONE.
|
||||
[-] Applying patch "04-rtt.patch"... DONE.
|
||||
[-] Applying patch "01-panic_console.patch"... DONE.
|
||||
[-] Applying patch "02-timer.patch"... DONE.
|
||||
[-] Applying patch "03-public_syscalls.patch"... DONE.
|
||||
[-] Applying patch "04-bigger_heap.patch"... DONE.
|
||||
Signature ok
|
||||
subject=CN = Google OpenSK CA
|
||||
Getting Private key
|
||||
Signature ok
|
||||
subject=CN = Google OpenSK Hacker Edition
|
||||
Getting CA Private Key
|
||||
info: syncing channel updates for 'nightly-2020-01-16-x86_64-unknown-linux-gnu'
|
||||
|
||||
nightly-2020-01-16-x86_64-unknown-linux-gnu unchanged - rustc 1.42.0-nightly (3291ae339 2020-01-15)
|
||||
|
||||
Requirement already up-to-date: tockloader in /usr/lib/python3/dist-packages/tockloader-1.4.0.dev0-py3.7.egg (1.4.0.dev0)
|
||||
Requirement already satisfied, skipping upgrade: argcomplete>=1.8.2 in /usr/lib/python3/dist-packages (from tockloader) (1.10.0)
|
||||
Requirement already satisfied, skipping upgrade: colorama>=0.3.7 in /usr/lib/python3/dist-packages (from tockloader) (0.3.7)
|
||||
Requirement already satisfied, skipping upgrade: crcmod>=1.7 in /usr/lib/python3/dist-packages (from tockloader) (1.7)
|
||||
Requirement already satisfied, skipping upgrade: pyserial>=3.0.1 in /usr/lib/python3/dist-packages (from tockloader) (3.4)
|
||||
Requirement already satisfied, skipping upgrade: pytoml>=0.1.11 in /usr/lib/python3/dist-packages (from tockloader) (0.1.21)
|
||||
info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date
|
||||
Updating crates.io index
|
||||
Ignored package `elf2tab v0.4.0` is already installed, use --force to override
|
||||
```
|
||||
|
||||
The script performs the following steps:
|
||||
|
||||
1. Make sure that the git submodules are checked out
|
||||
|
||||
1. Apply our patches that haven't yet been merged upstream to both
|
||||
[Tock](https://github.com/tock/tock) and
|
||||
[libtock-rs](https://github.com/tock/libtock-rs)
|
||||
|
||||
1. Generate a self-signed certificate authority as well as a private key and a
|
||||
corresponding certificate for your OpenSK key signed by this CA. You will be
|
||||
able to replace them with your own certificate and private key.
|
||||
|
||||
1. Ensure that your Rust toolchain is using the same version that we tested
|
||||
OpenSK with.
|
||||
|
||||
1. Install [tockloader](https://github.com/tock/tockloader).
|
||||
|
||||
1. Ensure that the Rust toolchain can compile code for ARM devices.
|
||||
|
||||
### Replacing the certificates
|
||||
|
||||
All the generated certificates and private keys are stored in the directory
|
||||
`crypto_data/`.
|
||||
|
||||
This is the expected content after running our `setup.sh` script:
|
||||
|
||||
File | Purpose
|
||||
----------------- | --------------------------------------------------------
|
||||
`opensk_ca.csr` | Certificate sign request for the Root CA
|
||||
`opensk_ca.key` | ECC secp256r1 private key used for the Root CA
|
||||
`opensk_ca.pem` | PEM encoded certificate of the Root CA
|
||||
`opensk_ca.srl` | File generated by OpenSSL
|
||||
`opensk_cert.csr` | Certificate sign request for the attestation certificate
|
||||
`opensk_cert.pem` | PEM encoded certificate used for the authenticator
|
||||
`opensk.key` | ECC secp256r1 private key used for the autenticator
|
||||
|
||||
If you want to use your own attestation certificate and private key, simply
|
||||
replace `opensk_cert.pem` and `opensk.key` files.
|
||||
|
||||
Our build script is responsible for converting `opensk_cert.pem` and
|
||||
`opensk.key` files into the following Rust file: `src/ctap/key_material.rs`.
|
||||
|
||||
### Flashing a firmware
|
||||
|
||||
#### Nordic nRF52840-DK board
|
||||
|
||||

|
||||
|
||||
1. Connect a micro USB cable to the JTAG USB port.
|
||||
|
||||
1. Run our script for compiling/flashing your device (_output may differ_):
|
||||
|
||||
```shell
|
||||
$ board=nrf52840dk ./deploy.sh app os
|
||||
make: Entering directory './third_party/tock/boards/nordic/nrf52840dk'
|
||||
Compiling kernel v0.1.0 (./third_party/tock/kernel)
|
||||
Compiling cortexm v0.1.0 (./third_party/tock/arch/cortex-m)
|
||||
Compiling nrf5x v0.1.0 (./third_party/tock/chips/nrf5x)
|
||||
Compiling capsules v0.1.0 (./third_party/tock/capsules)
|
||||
Compiling cortexm4 v0.1.0 (./third_party/tock/arch/cortex-m4)
|
||||
Compiling nrf52 v0.1.0 (./third_party/tock/chips/nrf52)
|
||||
Compiling nrf52840 v0.1.0 (./third_party/tock/chips/nrf52840)
|
||||
Compiling components v0.1.0 (./third_party/tock/boards/components)
|
||||
Compiling nrf52dk_base v0.1.0 (./third_party/tock/boards/nordic/nrf52dk_base)
|
||||
Compiling nrf52840dk v0.1.0 (./third_party/tock/boards/nordic/nrf52840dk)
|
||||
Finished release [optimized + debuginfo] target(s) in 11.28s
|
||||
text data bss dec hex filename
|
||||
114688 1760 260384 376832 5c000 target/thumbv7em-none-eabi/release/nrf52840dk
|
||||
tockloader flash --address 0x00000 --jlink --board nrf52dk target/thumbv7em-none-eabi/release/nrf52840dk.bin
|
||||
[STATUS ] Flashing binar(y|ies) to board...
|
||||
[INFO ] Using known arch and jtag-device for known board nrf52dk
|
||||
[INFO ] Finished in 0.324 seconds
|
||||
|
||||
make: Leaving directory './third_party/tock/boards/nordic/nrf52840dk'
|
||||
[STATUS ] Preparing to uninstall apps...
|
||||
[INFO ] Using known arch and jtag-device for known board nrf52dk
|
||||
[ERROR ] No apps are installed on the board
|
||||
|
||||
Compiling libtock v0.1.0 (./third_party/libtock-rs)
|
||||
Compiling crypto v0.1.0 (./libraries/crypto)
|
||||
Compiling ctap2 v0.1.0 (.)
|
||||
Finished release [optimized] target(s) in 7.60s
|
||||
[STATUS ] Flashing binar(y|ies) to board...
|
||||
[INFO ] Using known arch and jtag-device for known board nrf52dk
|
||||
[INFO ] Finished in 0.305 seconds
|
||||
|
||||
[STATUS ] Installing app on the board...
|
||||
[INFO ] Using known arch and jtag-device for known board nrf52dk
|
||||
[INFO ] Finished in 0.975 seconds
|
||||
```
|
||||
|
||||
1. Connect a micro USB cable to the device USB port.
|
||||
|
||||
**Note**: Due to current limitations of our implementation and Tock, you may
|
||||
have to press the `BOOT/RESET` button, located next to the device USB port on
|
||||
the board in order to see your OpenSK device on your system.
|
||||
|
||||
#### Nordic nRF52840 Dongle
|
||||
|
||||

|
||||
|
||||
1. The JTAG probe used for programming won't provide power to the board.
|
||||
Therefore you will need to use a USB-A extension cable to power the dongle
|
||||
through its USB port.
|
||||
|
||||
1. Connect the TC2050 cable to the pads below the PCB:
|
||||
|
||||

|
||||
|
||||
1. You can use the retainer clip if you have one to avoid maintaining pressure
|
||||
between the board and the cable:
|
||||
|
||||

|
||||
|
||||
1. Run our script for compiling/flashing your device (_output may differ_):
|
||||
|
||||
```shell
|
||||
$ board=nrf52840_dongle ./deploy.sh app os
|
||||
make: Entering directory './third_party/tock/boards/nordic/nrf52840_dongle'
|
||||
Compiling kernel v0.1.0 (./third_party/tock/kernel)
|
||||
Compiling cortexm v0.1.0 (./third_party/tock/arch/cortex-m)
|
||||
Compiling nrf5x v0.1.0 (./third_party/tock/chips/nrf5x)
|
||||
Compiling capsules v0.1.0 (./third_party/tock/capsules)
|
||||
Compiling cortexm4 v0.1.0 (./third_party/tock/arch/cortex-m4)
|
||||
Compiling nrf52 v0.1.0 (./third_party/tock/chips/nrf52)
|
||||
Compiling nrf52840 v0.1.0 (./third_party/tock/chips/nrf52840)
|
||||
Compiling components v0.1.0 (./third_party/tock/boards/components)
|
||||
Compiling nrf52dk_base v0.1.0 (./third_party/tock/boards/nordic/nrf52dk_base)
|
||||
Compiling nrf52840_dongle v0.1.0 (./third_party/tock/boards/nordic/nrf52840_dongle)
|
||||
Finished release [optimized + debuginfo] target(s) in 10.47s
|
||||
text data bss dec hex filename
|
||||
110592 1688 252264 364544 59000 target/thumbv7em-none-eabi/release/nrf52840_dongle
|
||||
tockloader flash --address 0x00000 --jlink --board nrf52dk target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
|
||||
[STATUS ] Flashing binar(y|ies) to board...
|
||||
[INFO ] Using known arch and jtag-device for known board nrf52dk
|
||||
[INFO ] Finished in 0.296 seconds
|
||||
|
||||
make: Leaving directory './third_party/tock/boards/nordic/nrf52840_dongle'
|
||||
[STATUS ] Preparing to uninstall apps...
|
||||
[INFO ] Using known arch and jtag-device for known board nrf52dk
|
||||
[ERROR ] No apps are installed on the board
|
||||
|
||||
Compiling libtock v0.1.0 (./third_party/libtock-rs)
|
||||
Compiling crypto v0.1.0 (./libraries/crypto)
|
||||
Compiling ctap2 v0.1.0 (.)
|
||||
Finished release [optimized] target(s) in 7.60s
|
||||
[STATUS ] Flashing binar(y|ies) to board...
|
||||
[INFO ] Using known arch and jtag-device for known board nrf52dk
|
||||
[INFO ] Finished in 0.317 seconds
|
||||
|
||||
[STATUS ] Installing app on the board...
|
||||
[INFO ] Using known arch and jtag-device for known board nrf52dk
|
||||
[INFO ] Finished in 0.902 seconds
|
||||
```
|
||||
|
||||
1. Remove the programming cable and the USB-A extension cable.
|
||||
|
||||
### Installing the udev rule (Linux only)
|
||||
|
||||
By default on Linux, a USB device will require root privilege in order interact
|
||||
with it. As it is not recommended to run your web browser with such a high
|
||||
privileged account, we made a `udev` rule file to allow regular users to
|
||||
interact with OpenSK authenticators.
|
||||
|
||||
To install it, you need to execute the following commands:
|
||||
|
||||
```shell
|
||||
sudo cp rules.d/55-opensk.rules /etc/udev/rules.d/
|
||||
sudo udevadm control --reload
|
||||
```
|
||||
|
||||
Then, you will need to unplug and replug the key for the rule to trigger.
|
||||
Reference in New Issue
Block a user