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"
[build-dependencies]
sk-cbor = { path = "libraries/cbor" }
uuid = { version = "0.8", features = ["v4"] }
openssl = "0.10.36"
[profile.dev]
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");
// 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
// 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;
@@ -20,7 +27,9 @@ 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");
@@ -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();
}

View File

@@ -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.

View File

@@ -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;
@@ -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;

View File

@@ -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] =
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 {
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 {
self.partition.length()
}

View File

@@ -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;

View File

@@ -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)}
@@ -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}"