Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ with_nfc = ["libtock_drivers/with_nfc"]
enum-iterator = "0.6.0"

[build-dependencies]
sk-cbor = { path = "libraries/cbor" }
uuid = { version = "0.8", features = ["v4"] }
openssl = "0.10.36"

[profile.dev]
panic = "abort"
Expand Down
43 changes: 42 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2019 Google LLC
// Copyright 2019-2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -12,15 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate alloc;

use openssl::bn;
use openssl::ec;
use openssl::nid;
use sk_cbor::cbor_map;
use std::env;
use std::fs;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::path::Path;
use uuid::Uuid;

fn main() {
const UPGRADE_FILE: &str = "crypto_data/opensk_upgrade_pub.pem";
println!("cargo:rerun-if-changed=crypto_data/aaguid.txt");
println!("cargo:rerun-if-changed={}", UPGRADE_FILE);
println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=nrf52840_layout.ld");

Expand All @@ -34,4 +43,36 @@ fn main() {
content.truncate(36);
let aaguid = Uuid::parse_str(&content).unwrap();
aaguid_bin_file.write_all(aaguid.as_bytes()).unwrap();

// COSE encoding the public key, then write it out.
let pem_bytes = fs::read(UPGRADE_FILE).unwrap();
let ec_key = ec::EcKey::public_key_from_pem(&pem_bytes).ok().unwrap();
let group = ec::EcGroup::from_curve_name(nid::Nid::X9_62_PRIME256V1).unwrap();
let conversion_form = ec::PointConversionForm::UNCOMPRESSED;
let mut ctx = bn::BigNumContext::new().unwrap();
let raw_bytes = ec_key
.public_key()
.to_bytes(&group, conversion_form, &mut ctx)
.unwrap();
const POINT_LEN: usize = 32;
assert_eq!(raw_bytes.len(), 1 + 2 * POINT_LEN);
assert_eq!(raw_bytes[0], 0x04);
let x_bytes = &raw_bytes[1..][..POINT_LEN];
let y_bytes = &raw_bytes[1 + POINT_LEN..][..POINT_LEN];

const EC2_KEY_TYPE: i64 = 2;
const P_256_CURVE: i64 = 1;
const ES256_ALGORITHM: i64 = -7;
let pub_key_cbor = sk_cbor::cbor_map! {
1 => EC2_KEY_TYPE,
3 => ES256_ALGORITHM,
-1 => P_256_CURVE,
-2 => x_bytes,
-3 => y_bytes,
};
let mut cbor_bytes = vec![];
sk_cbor::writer::write(pub_key_cbor, &mut cbor_bytes).unwrap();
let upgrade_pubkey_path = Path::new(&out_dir).join("opensk_upgrade_pubkey_cbor.bin");
let mut upgrade_pub_bin_file = File::create(&upgrade_pubkey_path).unwrap();
upgrade_pub_bin_file.write_all(&cbor_bytes).unwrap();
}
22 changes: 12 additions & 10 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,18 @@ All the generated certificates and private keys are stored in the directory

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
`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
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
`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
`opensk_upgrade.key` | Private key for signing upgrades through CTAP
`opensk_upgrade_pub.pem` | Public key added to the firmware for verifying upgrades

If you want to use your own attestation certificate and private key, simply
replace `opensk_cert.pem` and `opensk.key` files.
Expand Down
21 changes: 1 addition & 20 deletions src/ctap/data_formats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use alloc::string::String;
use alloc::vec::Vec;
use arrayref::array_ref;
use core::convert::TryFrom;
use core::fmt;
use crypto::{ecdh, ecdsa};
#[cfg(test)]
use enum_iterator::IntoEnumIterator;
Expand Down Expand Up @@ -841,30 +840,12 @@ impl TryFrom<CoseKey> for ecdsa::PubKey {
/// Data structure for receiving a signature.
///
/// See https://datatracker.ietf.org/doc/html/rfc8152#appendix-C.1.1 for reference.
///
/// TODO derive Debug and PartialEq with compiler version 1.47
#[derive(Clone)]
#[derive(Clone, Debug, PartialEq)]
pub struct CoseSignature {
pub algorithm: SignatureAlgorithm,
pub bytes: [u8; ecdsa::Signature::BYTES_LENGTH],
}

impl fmt::Debug for CoseSignature {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("CoseSignature")
.field("algorithm", &self.algorithm)
.field("bytes", &self.bytes.to_vec())
.finish()
}
}

impl PartialEq for CoseSignature {
fn eq(&self, other: &CoseSignature) -> bool {
self.algorithm == other.algorithm && self.bytes[..] == other.bytes[..]
}
}

impl TryFrom<cbor::Value> for CoseSignature {
type Error = Ctap2StatusCode;

Expand Down
3 changes: 3 additions & 0 deletions src/ctap/key_material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

pub const ATTESTATION_PRIVATE_KEY_LENGTH: usize = 32;
pub const AAGUID_LENGTH: usize = 16;
pub const _UPGRADE_PUBLIC_KEY_LENGTH: usize = 77;

pub const AAGUID: &[u8; AAGUID_LENGTH] =
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_aaguid.bin"));
pub const _UPGRADE_PUBLIC_KEY: &[u8; _UPGRADE_PUBLIC_KEY_LENGTH] =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last time, after discussion, I realized that #[warn(dead_code)] (and not #[allow(dead_code)]) might be more convenient (no need to change names). As you want.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that, and realized that we error on warning. So it's either allow or renaming. And in this case, it wasn't too much work to rename.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right this is not great. We might want to remove that rule in develop branch.

include_bytes!(concat!(env!("OUT_DIR"), "/opensk_upgrade_pubkey_cbor.bin"));
4 changes: 4 additions & 0 deletions src/embedded_flash/buffer_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ impl UpgradeStorage for BufferUpgradeStorage {
}
}

fn partition_address(&self) -> usize {
0x60000
}

fn partition_length(&self) -> usize {
PARTITION_LENGTH
}
Expand Down
4 changes: 4 additions & 0 deletions src/embedded_flash/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ impl UpgradeStorage for SyscallUpgradeStorage {
}
}

fn partition_address(&self) -> usize {
self.partition.start()
}

fn partition_length(&self) -> usize {
self.partition.length()
}
Expand Down
3 changes: 3 additions & 0 deletions src/embedded_flash/upgrade_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub trait UpgradeStorage {
/// Returns [`StorageError::OutOfBounds`] if the data does not fit the partition.
fn write_partition(&mut self, offset: usize, data: &[u8]) -> StorageResult<()>;

/// Returns the address of the partition.
fn partition_address(&self) -> usize;

/// Returns the length of the partition.
fn partition_length(&self) -> usize;

Expand Down
16 changes: 16 additions & 0 deletions tools/gen_key_materials.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ generate_crypto_materials () {
local opensk_key=crypto_data/opensk.key
local opensk_cert_name=crypto_data/opensk_cert

# The upgrade private key is used for signing, the corresponding public key
# will be COSE encoded and embedded into the firmware.
local opensk_upgrade=crypto_data/opensk_upgrade.key
local opensk_upgrade_pub=crypto_data/opensk_upgrade_pub.pem

# Allow invoker to override the command with a full path.
local openssl=${OPENSSL:-$(which openssl)}

Expand Down Expand Up @@ -88,6 +93,17 @@ generate_crypto_materials () {
-sha256
fi

if [ "${force_generate}" = "Y" -o ! -f "${opensk_upgrade}" ]
then
"${openssl}" ecparam -genkey -name prime256v1 -out "${opensk_upgrade}"
rm -f "${opensk_upgrade_pub}"
fi

if [ "${force_generate}" = "Y" -o ! -f "${opensk_upgrade_pub}" ]
then
"${openssl}" ec -in "${opensk_upgrade}" -pubout -out "${opensk_upgrade_pub}"
fi

if [ "${force_generate}" = "Y" -o ! -f "${aaguid_file}" ]
then
uuidgen > "${aaguid_file}"
Expand Down