Skip to content

Commit

Permalink
Merge pull request google#239 from jmichelp/transparency
Browse files Browse the repository at this point in the history
Add vendor commands to inject crypto materials
  • Loading branch information
jmichelp authored Dec 16, 2020
2 parents 9864d25 + 712fa0f commit 420d038
Show file tree
Hide file tree
Showing 20 changed files with 1,281 additions and 130 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ Cargo.lock
/reproducible/binaries.sha256sum
/reproducible/elf2tab.txt
/reproducible/reproduced.tar
__pycache__
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ctap2"
version = "0.1.0"
version = "1.0.0"
authors = [
"Fabian Kaczmarczyck <[email protected]>",
"Guillaume Endignoux <[email protected]>",
Expand Down Expand Up @@ -35,7 +35,6 @@ elf2tab = "0.6.0"
enum-iterator = "0.6.0"

[build-dependencies]
openssl = "0.10"
uuid = { version = "0.8", features = ["v4"] }

[profile.dev]
Expand Down
43 changes: 27 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# <img alt="OpenSK logo" src="docs/img/OpenSK.svg" width="200px">

[![Build Status](https://travis-ci.org/google/OpenSK.svg?branch=master)](https://travis-ci.org/google/OpenSK)
![markdownlint](https://github.com/google/OpenSK/workflows/markdownlint/badge.svg?branch=master)
![pylint](https://github.com/google/OpenSK/workflows/pylint/badge.svg?branch=master)
![Cargo check](https://github.com/google/OpenSK/workflows/Cargo%20check/badge.svg?branch=master)
Expand Down Expand Up @@ -31,7 +30,8 @@ our implementation was not reviewed nor officially tested and doesn't claim to
be FIDO Certified.
We started adding features of the upcoming next version of the
[CTAP2.1 specifications](https://fidoalliance.org/specs/fido2/fido-client-to-authenticator-protocol-v2.1-rd-20191217.html).
The development is currently between 2.0 and 2.1, with updates hidden behind a feature flag.
The development is currently between 2.0 and 2.1, with updates hidden behind
a feature flag.
Please add the flag `--ctap2.1` to the deploy command to include them.

### Cryptography
Expand All @@ -58,8 +58,8 @@ For a more detailed guide, please refer to our
./setup.sh
```

2. Next step is to install Tock OS as well as the OpenSK application on your
board (**Warning**: it will erase the locally stored credentials). Run:
1. Next step is to install Tock OS as well as the OpenSK application on your
board. Run:

```shell
# Nordic nRF52840-DK board
Expand All @@ -68,7 +68,17 @@ For a more detailed guide, please refer to our
./deploy.py --board=nrf52840_dongle --opensk
```

3. On Linux, you may want to avoid the need for `root` privileges to interact
1. Finally you need to inject the cryptographic material if you enabled
batch attestation or CTAP1/U2F compatibility (which is the case by
default):

```shell
./tools/configure.py \
--certificate=crypto_data/opensk_cert.pem \
--private-key=crypto_data/opensk.key
```

1. On Linux, you may want to avoid the need for `root` privileges to interact
with the key. For that purpose we provide a udev rule file that can be
installed with the following command:

Expand Down Expand Up @@ -148,7 +158,7 @@ operation.
The additional output looks like the following.
```
```text
# Allocation of 256 byte(s), aligned on 1 byte(s). The allocated address is
# 0x2002401c. After this operation, 2 pointers have been allocated, totalling
# 384 bytes (the total heap usage may be larger, due to alignment and
Expand All @@ -163,12 +173,12 @@ A tool is provided to analyze such reports, in `tools/heapviz`. This tool
parses the console output, identifies the lines corresponding to (de)allocation
operations, and first computes some statistics:
- Address range used by the heap over this run of the program,
- Peak heap usage (how many useful bytes are allocated),
- Peak heap consumption (how many bytes are used by the heap, including
unavailable bytes between allocated blocks, due to alignment constraints and
memory fragmentation),
- Fragmentation overhead (difference between heap consumption and usage).
* Address range used by the heap over this run of the program,
* Peak heap usage (how many useful bytes are allocated),
* Peak heap consumption (how many bytes are used by the heap, including
unavailable bytes between allocated blocks, due to alignment constraints and
memory fragmentation),
* Fragmentation overhead (difference between heap consumption and usage).
Then, the `heapviz` tool displays an animated "movie" of the allocated bytes in
heap memory. Each frame in this "movie" shows bytes that are currently
Expand All @@ -177,10 +187,11 @@ allocated. A new frame is generated for each (de)allocation operation. This tool
uses the `ncurses` library, that you may have to install beforehand.
You can control the tool with the following parameters:
- `--logfile` (required) to provide the file which contains the console output
to parse,
- `--fps` (optional) to customize the number of frames per second in the movie
animation.
* `--logfile` (required) to provide the file which contains the console output
to parse,
* `--fps` (optional) to customize the number of frames per second in the movie
animation.
```shell
cargo run --manifest-path tools/heapviz/Cargo.toml -- --logfile console.log --fps 50
Expand Down
2 changes: 1 addition & 1 deletion boards/nordic/nrf52840_mdk_dfu/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static STRINGS: &'static [&'static str] = &[
// Product
"OpenSK",
// Serial number
"v0.1",
"v1.0",
];

// State for loading and holding applications.
Expand Down
59 changes: 0 additions & 59 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use openssl::asn1;
use openssl::ec;
use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::x509;
use std::env;
use std::fs::File;
use std::io::Read;
Expand All @@ -25,65 +20,11 @@ use std::path::Path;
use uuid::Uuid;

fn main() {
println!("cargo:rerun-if-changed=crypto_data/opensk.key");
println!("cargo:rerun-if-changed=crypto_data/opensk_cert.pem");
println!("cargo:rerun-if-changed=crypto_data/aaguid.txt");

let out_dir = env::var_os("OUT_DIR").unwrap();
let priv_key_bin_path = Path::new(&out_dir).join("opensk_pkey.bin");
let cert_bin_path = Path::new(&out_dir).join("opensk_cert.bin");
let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin");

// Load the OpenSSL PEM ECC key
let ecc_data = include_bytes!("crypto_data/opensk.key");
let pkey =
ec::EcKey::private_key_from_pem(ecc_data).expect("Failed to load OpenSK private key file");

// Check key validity
pkey.check_key().unwrap();
assert_eq!(pkey.group().curve_name(), Some(Nid::X9_62_PRIME256V1));

// Private keys generated by OpenSSL have variable size but we only handle
// constant size. Serialization is done in big endian so if the size is less
// than 32 bytes, we need to prepend with null bytes.
// If the size is 33 bytes, this means the serialized BigInt is negative.
// Any other size is invalid.
let priv_key_hex = pkey.private_key().to_hex_str().unwrap();
let priv_key_vec = pkey.private_key().to_vec();
let key_len = priv_key_vec.len();

assert!(
key_len <= 33,
"Invalid private key (too big): {} ({:#?})",
priv_key_hex,
priv_key_vec,
);

// Copy OpenSSL generated key to our vec, starting from the end
let mut output_vec = [0u8; 32];
let min_key_len = std::cmp::min(key_len, 32);
output_vec[32 - min_key_len..].copy_from_slice(&priv_key_vec[key_len - min_key_len..]);

// Create the raw private key out of the OpenSSL data
let mut priv_key_bin_file = File::create(&priv_key_bin_path).unwrap();
priv_key_bin_file.write_all(&output_vec).unwrap();

// Convert the PEM certificate to DER and extract the serial for AAGUID
let input_pem_cert = include_bytes!("crypto_data/opensk_cert.pem");
let cert = x509::X509::from_pem(input_pem_cert).expect("Failed to load OpenSK certificate");

// Do some sanity check on the certificate
assert!(cert
.public_key()
.unwrap()
.public_eq(&PKey::from_ec_key(pkey).unwrap()));
let now = asn1::Asn1Time::days_from_now(0).unwrap();
assert!(cert.not_after() > now);
assert!(cert.not_before() <= now);

let mut cert_bin_file = File::create(&cert_bin_path).unwrap();
cert_bin_file.write_all(&cert.to_der().unwrap()).unwrap();

let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap();
let mut aaguid_txt_file = File::open("crypto_data/aaguid.txt").unwrap();
let mut content = String::new();
Expand Down
43 changes: 43 additions & 0 deletions deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,22 @@ def run(self):
check=False,
timeout=None,
).returncode

# Configure OpenSK through vendor specific command if needed
if any([
self.args.lock_device,
self.args.config_cert,
self.args.config_pkey,
]):
# pylint: disable=g-import-not-at-top,import-outside-toplevel
import tools.configure
tools.configure.main(
argparse.Namespace(
batch=False,
certificate=self.args.config_cert,
priv_key=self.args.config_pkey,
lock=self.args.lock_device,
))
return 0


Expand Down Expand Up @@ -770,6 +786,33 @@ def main(args):
help=("Erases the persistent storage when installing an application. "
"All stored data will be permanently lost."),
)
main_parser.add_argument(
"--lock-device",
action="store_true",
default=False,
dest="lock_device",
help=("Try to disable JTAG at the end of the operations. This "
"operation may fail if the device is already locked or if "
"the certificate/private key are not programmed."),
)
main_parser.add_argument(
"--inject-certificate",
default=None,
metavar="PEM_FILE",
type=argparse.FileType("rb"),
dest="config_cert",
help=("If this option is set, the corresponding certificate "
"will be programmed into the key as the last operation."),
)
main_parser.add_argument(
"--inject-private-key",
default=None,
metavar="PEM_FILE",
type=argparse.FileType("rb"),
dest="config_pkey",
help=("If this option is set, the corresponding private key "
"will be programmed into the key as the last operation."),
)
main_parser.add_argument(
"--programmer",
metavar="METHOD",
Expand Down
9 changes: 6 additions & 3 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ This is the expected content after running our `setup.sh` script:

File | Purpose
----------------- | --------------------------------------------------------
`aaguid.txt` | Text file containaing the AAGUID value
`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
Expand All @@ -136,9 +137,11 @@ File | Purpose
If you want to use your own attestation certificate and private key, simply
replace `opensk_cert.pem` and `opensk.key` files.

Our build script `build.rs` is responsible for converting `opensk_cert.pem` and
`opensk.key` files into raw data that is then used by the Rust file:
`src/ctap/key_material.rs`.
Our build script `build.rs` is responsible for converting the `aaguid.txt` file
into raw data that is then used by the Rust file `src/ctap/key_material.rs`.

Our configuration script `tools/configure.py` is responsible for configuring
an OpenSK device with the correct certificate and private key.

### Flashing a firmware

Expand Down
4 changes: 2 additions & 2 deletions patches/tock/02-usb.patch
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ index d72d20482..118ea6d68 100644
+ // Product
+ "OpenSK",
+ // Serial number
+ "v0.1",
+ "v1.0",
+];
+
// State for loading and holding applications.
Expand Down Expand Up @@ -189,7 +189,7 @@ index 2ebb384d8..4a7bfffdd 100644
+ // Product
+ "OpenSK",
+ // Serial number
+ "v0.1",
+ "v1.0",
+];
+
// State for loading and holding applications.
Expand Down
100 changes: 100 additions & 0 deletions patches/tock/06-update-uicr.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
diff --git a/chips/nrf52/src/uicr.rs b/chips/nrf52/src/uicr.rs
index 6bb6c86..3bb8b5a 100644
--- a/chips/nrf52/src/uicr.rs
+++ b/chips/nrf52/src/uicr.rs
@@ -1,38 +1,45 @@
//! User information configuration registers
-//!
-//! Minimal implementation to support activation of the reset button on
-//! nRF52-DK.
+

use enum_primitive::cast::FromPrimitive;
-use kernel::common::registers::{register_bitfields, ReadWrite};
+use kernel::common::registers::{register_bitfields, register_structs, ReadWrite};
use kernel::common::StaticRef;
+use kernel::hil;
+use kernel::ReturnCode;

use crate::gpio::Pin;

const UICR_BASE: StaticRef<UicrRegisters> =
- unsafe { StaticRef::new(0x10001200 as *const UicrRegisters) };
-
-#[repr(C)]
-struct UicrRegisters {
- /// Mapping of the nRESET function (see POWER chapter for details)
- /// - Address: 0x200 - 0x204
- pselreset0: ReadWrite<u32, Pselreset::Register>,
- /// Mapping of the nRESET function (see POWER chapter for details)
- /// - Address: 0x204 - 0x208
- pselreset1: ReadWrite<u32, Pselreset::Register>,
- /// Access Port protection
- /// - Address: 0x208 - 0x20c
- approtect: ReadWrite<u32, ApProtect::Register>,
- /// Setting of pins dedicated to NFC functionality: NFC antenna or GPIO
- /// - Address: 0x20c - 0x210
- nfcpins: ReadWrite<u32, NfcPins::Register>,
- _reserved1: [u32; 60],
- /// External circuitry to be supplied from VDD pin.
- /// - Address: 0x300 - 0x304
- extsupply: ReadWrite<u32, ExtSupply::Register>,
- /// GPIO reference voltage
- /// - Address: 0x304 - 0x308
- regout0: ReadWrite<u32, RegOut::Register>,
+ unsafe { StaticRef::new(0x10001000 as *const UicrRegisters) };
+
+register_structs! {
+ UicrRegisters {
+ (0x000 => _reserved1),
+ /// Reserved for Nordic firmware design
+ (0x014 => nrffw: [ReadWrite<u32>; 13]),
+ (0x048 => _reserved2),
+ /// Reserved for Nordic hardware design
+ (0x050 => nrfhw: [ReadWrite<u32>; 12]),
+ /// Reserved for customer
+ (0x080 => customer: [ReadWrite<u32>; 32]),
+ (0x100 => _reserved3),
+ /// Mapping of the nRESET function (see POWER chapter for details)
+ (0x200 => pselreset0: ReadWrite<u32, Pselreset::Register>),
+ /// Mapping of the nRESET function (see POWER chapter for details)
+ (0x204 => pselreset1: ReadWrite<u32, Pselreset::Register>),
+ /// Access Port protection
+ (0x208 => approtect: ReadWrite<u32, ApProtect::Register>),
+ /// Setting of pins dedicated to NFC functionality: NFC antenna or GPIO
+ /// - Address: 0x20c - 0x210
+ (0x20c => nfcpins: ReadWrite<u32, NfcPins::Register>),
+ (0x210 => debugctrl: ReadWrite<u32, DebugControl::Register>),
+ (0x214 => _reserved4),
+ /// External circuitry to be supplied from VDD pin.
+ (0x300 => extsupply: ReadWrite<u32, ExtSupply::Register>),
+ /// GPIO reference voltage
+ (0x304 => regout0: ReadWrite<u32, RegOut::Register>),
+ (0x308 => @END),
+ }
}

register_bitfields! [u32,
@@ -58,6 +65,21 @@ register_bitfields! [u32,
DISABLED = 0xff
]
],
+ /// Processor debug control
+ DebugControl [
+ CPUNIDEN OFFSET(0) NUMBITS(8) [
+ /// Enable
+ ENABLED = 0xff,
+ /// Disable
+ DISABLED = 0x00
+ ],
+ CPUFPBEN OFFSET(8) NUMBITS(8) [
+ /// Enable
+ ENABLED = 0xff,
+ /// Disable
+ DISABLED = 0x00
+ ]
+ ],
/// Setting of pins dedicated to NFC functionality: NFC antenna or GPIO
NfcPins [
/// Setting pins dedicated to NFC functionality

Loading

0 comments on commit 420d038

Please sign in to comment.