Upgrade signing key generation (#379)

* adds the upgrade signing key generation and the partition offset

* use openssl in build.rs instead
This commit is contained in:
kaczmarczyck
2021-09-15 21:25:19 +02:00
committed by GitHub
parent 7a975acf33
commit 596b47886c
9 changed files with 87 additions and 31 deletions

View File

@@ -33,7 +33,9 @@ with_nfc = ["libtock_drivers/with_nfc"]
enum-iterator = "0.6.0" enum-iterator = "0.6.0"
[build-dependencies] [build-dependencies]
sk-cbor = { path = "libraries/cbor" }
uuid = { version = "0.8", features = ["v4"] } uuid = { version = "0.8", features = ["v4"] }
openssl = "0.10.36"
[profile.dev] [profile.dev]
panic = "abort" panic = "abort"

View File

@@ -1,4 +1,4 @@
// Copyright 2019 Google LLC // Copyright 2019-2021 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -12,7 +12,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // 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::env;
use std::fs;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
@@ -20,7 +27,9 @@ use std::path::Path;
use uuid::Uuid; use uuid::Uuid;
fn main() { 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=crypto_data/aaguid.txt");
println!("cargo:rerun-if-changed={}", UPGRADE_FILE);
println!("cargo:rerun-if-changed=layout.ld"); println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=nrf52840_layout.ld"); println!("cargo:rerun-if-changed=nrf52840_layout.ld");
@@ -34,4 +43,36 @@ fn main() {
content.truncate(36); content.truncate(36);
let aaguid = Uuid::parse_str(&content).unwrap(); let aaguid = Uuid::parse_str(&content).unwrap();
aaguid_bin_file.write_all(aaguid.as_bytes()).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();
} }

View File

@@ -125,7 +125,7 @@ All the generated certificates and private keys are stored in the directory
This is the expected content after running our `setup.sh` script: This is the expected content after running our `setup.sh` script:
File | Purpose File | Purpose
----------------- | -------------------------------------------------------- ------------------------ | --------------------------------------------------------
`aaguid.txt` | Text file containaing the AAGUID value `aaguid.txt` | Text file containaing the AAGUID value
`opensk_ca.csr` | Certificate sign request for the Root CA `opensk_ca.csr` | Certificate sign request for the Root CA
`opensk_ca.key` | ECC secp256r1 private key used for the Root CA `opensk_ca.key` | ECC secp256r1 private key used for the Root CA
@@ -134,6 +134,8 @@ File | Purpose
`opensk_cert.csr` | Certificate sign request for the attestation certificate `opensk_cert.csr` | Certificate sign request for the attestation certificate
`opensk_cert.pem` | PEM encoded certificate used for the authenticator `opensk_cert.pem` | PEM encoded certificate used for the authenticator
`opensk.key` | ECC secp256r1 private key used for the autenticator `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 If you want to use your own attestation certificate and private key, simply
replace `opensk_cert.pem` and `opensk.key` files. replace `opensk_cert.pem` and `opensk.key` files.

View File

@@ -17,7 +17,6 @@ use alloc::string::String;
use alloc::vec::Vec; use alloc::vec::Vec;
use arrayref::array_ref; use arrayref::array_ref;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt;
use crypto::{ecdh, ecdsa}; use crypto::{ecdh, ecdsa};
#[cfg(test)] #[cfg(test)]
use enum_iterator::IntoEnumIterator; use enum_iterator::IntoEnumIterator;
@@ -841,30 +840,12 @@ impl TryFrom<CoseKey> for ecdsa::PubKey {
/// Data structure for receiving a signature. /// Data structure for receiving a signature.
/// ///
/// See https://datatracker.ietf.org/doc/html/rfc8152#appendix-C.1.1 for reference. /// See https://datatracker.ietf.org/doc/html/rfc8152#appendix-C.1.1 for reference.
/// #[derive(Clone, Debug, PartialEq)]
/// TODO derive Debug and PartialEq with compiler version 1.47
#[derive(Clone)]
pub struct CoseSignature { pub struct CoseSignature {
pub algorithm: SignatureAlgorithm, pub algorithm: SignatureAlgorithm,
pub bytes: [u8; ecdsa::Signature::BYTES_LENGTH], 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 { impl TryFrom<cbor::Value> for CoseSignature {
type Error = Ctap2StatusCode; type Error = Ctap2StatusCode;

View File

@@ -14,6 +14,9 @@
pub const ATTESTATION_PRIVATE_KEY_LENGTH: usize = 32; pub const ATTESTATION_PRIVATE_KEY_LENGTH: usize = 32;
pub const AAGUID_LENGTH: usize = 16; pub const AAGUID_LENGTH: usize = 16;
pub const _UPGRADE_PUBLIC_KEY_LENGTH: usize = 77;
pub const AAGUID: &[u8; AAGUID_LENGTH] = pub const AAGUID: &[u8; AAGUID_LENGTH] =
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_aaguid.bin")); include_bytes!(concat!(env!("OUT_DIR"), "/opensk_aaguid.bin"));
pub const _UPGRADE_PUBLIC_KEY: &[u8; _UPGRADE_PUBLIC_KEY_LENGTH] =
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_upgrade_pubkey_cbor.bin"));

View File

@@ -57,6 +57,10 @@ impl UpgradeStorage for BufferUpgradeStorage {
} }
} }
fn partition_address(&self) -> usize {
0x60000
}
fn partition_length(&self) -> usize { fn partition_length(&self) -> usize {
PARTITION_LENGTH PARTITION_LENGTH
} }

View File

@@ -317,6 +317,10 @@ impl UpgradeStorage for SyscallUpgradeStorage {
} }
} }
fn partition_address(&self) -> usize {
self.partition.start()
}
fn partition_length(&self) -> usize { fn partition_length(&self) -> usize {
self.partition.length() self.partition.length()
} }

View File

@@ -34,6 +34,9 @@ pub trait UpgradeStorage {
/// Returns [`StorageError::OutOfBounds`] if the data does not fit the partition. /// Returns [`StorageError::OutOfBounds`] if the data does not fit the partition.
fn write_partition(&mut self, offset: usize, data: &[u8]) -> StorageResult<()>; 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. /// Returns the length of the partition.
fn partition_length(&self) -> usize; fn partition_length(&self) -> usize;

View File

@@ -26,6 +26,11 @@ generate_crypto_materials () {
local opensk_key=crypto_data/opensk.key local opensk_key=crypto_data/opensk.key
local opensk_cert_name=crypto_data/opensk_cert 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. # Allow invoker to override the command with a full path.
local openssl=${OPENSSL:-$(which openssl)} local openssl=${OPENSSL:-$(which openssl)}
@@ -88,6 +93,17 @@ generate_crypto_materials () {
-sha256 -sha256
fi 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}" ] if [ "${force_generate}" = "Y" -o ! -f "${aaguid_file}" ]
then then
uuidgen > "${aaguid_file}" uuidgen > "${aaguid_file}"