Skip to content

Commit

Permalink
Fix pathLenConstraint for cert chain (#901)
Browse files Browse the repository at this point in the history
Previously, all pathLenConstraints were set to 0, which will always fail
verification. Update pathLenConstraint to
`IDevID (5) -> LDevID (4) -> FMC ALias (3) -> RT Alias (2)`.

Additionally

* Add AuthorityKeyIdentifier to the FMC Alias Key.
* Add tests to ensure openssl can verify Caliptra's cert chain.
* Autogenerate collateral for fake ROM
  • Loading branch information
jhand2 authored Oct 5, 2023
1 parent c9fdb51 commit 69c4614
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 67 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion fmc/src/flow/rt_alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ impl RtAliasLayer {
fn dice_input_from_hand_off(env: &mut FmcEnv) -> CaliptraResult<DiceInput> {
let auth_pub = HandOff::fmc_pub_key(env);
let auth_serial_number = X509::subj_sn(env, &auth_pub)?;
let auth_key_id = X509::subj_key_id(env, &auth_pub)?;
// Create initial output
let input = DiceInput {
cdi: HandOff::fmc_cdi(env),
Expand All @@ -141,7 +142,7 @@ impl RtAliasLayer {
pub_key: auth_pub,
},
auth_sn: auth_serial_number,
auth_key_id: [0u8; 20],
auth_key_id,
};

Ok(input)
Expand Down
1 change: 1 addition & 0 deletions rom/dev/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ zerocopy.workspace = true
[build-dependencies]
cfg-if.workspace = true
hex.workspace = true
x509-parser.workspace = true

[dev-dependencies]
caliptra-builder.workspace = true
Expand Down
64 changes: 62 additions & 2 deletions rom/dev/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Abstract:
--*/

use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

fn preprocess(filename: &str, defines: &[(String, String)]) -> Vec<u8> {
Expand All @@ -32,11 +34,31 @@ fn preprocess(filename: &str, defines: &[(String, String)]) -> Vec<u8> {
out.stdout
}

fn workspace_dir() -> PathBuf {
let output = std::process::Command::new(env!("CARGO"))
.arg("locate-project")
.arg("--workspace")
.arg("--message-format=plain")
.output()
.unwrap()
.stdout;
let cargo_path = Path::new(std::str::from_utf8(&output).unwrap().trim());
cargo_path.parent().unwrap().to_path_buf()
}

fn be_bytes_to_words(src: &[u8]) -> Vec<u32> {
let mut dst = Vec::<u32>::new();

for i in (0..src.len()).step_by(4) {
dst.push(u32::from_be_bytes(src[i..i + 4].try_into().unwrap()));
}

dst
}

fn main() {
if cfg!(not(feature = "std")) {
use std::env;
use std::fs;
use std::path::PathBuf;

let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
fs::write(out_dir.join("rom.ld"), include_bytes!("src/rom.ld")).unwrap();
Expand All @@ -57,4 +79,42 @@ fn main() {
println!("cargo:rerun-if-changed=src/start.S");
println!("cargo:rerun-if-changed=build.rs");
}

if cfg!(feature = "fake-rom") {
use x509_parser::nom::Parser;
use x509_parser::prelude::{FromDer, X509CertificateParser};
use x509_parser::signature_value::EcdsaSigValue;

let ws_dir = workspace_dir();
let ldev_file =
std::fs::read(ws_dir.join("test/tests/smoke_testdata/ldevid_cert.der")).unwrap();

let mut parser = X509CertificateParser::new();
let (_, cert) = parser.parse(&ldev_file).unwrap();

let tbs = cert.tbs_certificate.as_ref();
let (_, sig) = EcdsaSigValue::from_der(cert.signature_value.as_ref()).unwrap();

// Get words of Signature r and s
let mut r = sig.r.as_ref();
r = &r[r.len() - 48..];
let r_words = be_bytes_to_words(r);

let mut s = sig.s.as_ref();
s = &s[s.len() - 48..];
let s_words = be_bytes_to_words(s);

let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
std::fs::write(out_dir.join("ldev_tbs.der"), tbs).unwrap();
std::fs::write(
out_dir.join("ldev_sig_r_words.txt"),
format!("{:?}", r_words),
)
.unwrap();
std::fs::write(
out_dir.join("ldev_sig_s_words.txt"),
format!("{:?}", s_words),
)
.unwrap();
}
}
47 changes: 3 additions & 44 deletions rom/dev/src/flow/fake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,42 +40,7 @@ use caliptra_image_verify::ImageVerificationEnv;
use core::ops::Range;
use fw_processor::FirmwareProcessor;

const FAKE_LDEV_TBS: [u8; 533] = [
0x30, 0x82, 0x02, 0x11, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x25, 0xEE, 0xEF, 0x9A, 0x4C,
0x61, 0xD4, 0xB9, 0xE3, 0xD9, 0x4B, 0xEA, 0x46, 0xF9, 0xA1, 0x2A, 0xC6, 0x88, 0x7C, 0xE2, 0x30,
0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03, 0x30, 0x65, 0x31, 0x18, 0x30,
0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x43, 0x61, 0x6C, 0x69, 0x70, 0x74, 0x72, 0x61,
0x20, 0x49, 0x44, 0x65, 0x76, 0x49, 0x44, 0x31, 0x49, 0x30, 0x47, 0x06, 0x03, 0x55, 0x04, 0x05,
0x13, 0x40, 0x38, 0x45, 0x33, 0x43, 0x31, 0x41, 0x30, 0x35, 0x38, 0x46, 0x37, 0x30, 0x34, 0x41,
0x31, 0x31, 0x38, 0x32, 0x31, 0x46, 0x37, 0x42, 0x34, 0x38, 0x44, 0x33, 0x34, 0x30, 0x41, 0x45,
0x46, 0x39, 0x39, 0x44, 0x44, 0x41, 0x42, 0x41, 0x44, 0x43, 0x31, 0x30, 0x39, 0x30, 0x44, 0x37,
0x34, 0x44, 0x30, 0x35, 0x37, 0x46, 0x45, 0x43, 0x43, 0x46, 0x37, 0x33, 0x32, 0x39, 0x34, 0x45,
0x44, 0x36, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x32, 0x33, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x5A, 0x18, 0x0F, 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32,
0x33, 0x35, 0x39, 0x35, 0x39, 0x5A, 0x30, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
0x03, 0x0C, 0x0F, 0x43, 0x61, 0x6C, 0x69, 0x70, 0x74, 0x72, 0x61, 0x20, 0x4C, 0x44, 0x65, 0x76,
0x49, 0x44, 0x31, 0x49, 0x30, 0x47, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13, 0x40, 0x32, 0x31, 0x45,
0x45, 0x45, 0x46, 0x39, 0x41, 0x34, 0x43, 0x36, 0x31, 0x44, 0x34, 0x42, 0x39, 0x45, 0x33, 0x44,
0x39, 0x34, 0x42, 0x45, 0x41, 0x34, 0x36, 0x46, 0x39, 0x41, 0x31, 0x32, 0x41, 0x43, 0x36, 0x38,
0x38, 0x37, 0x43, 0x45, 0x32, 0x31, 0x38, 0x38, 0x35, 0x35, 0x39, 0x46, 0x34, 0x30, 0x46, 0x46,
0x39, 0x35, 0x37, 0x37, 0x37, 0x45, 0x38, 0x30, 0x31, 0x34, 0x38, 0x38, 0x39, 0x30, 0x76, 0x30,
0x10, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00,
0x22, 0x03, 0x62, 0x00, 0x04, 0x84, 0x2C, 0x00, 0xAF, 0x05, 0xAC, 0xCC, 0xEB, 0x14, 0x51, 0x4E,
0x2D, 0x37, 0xB0, 0xC3, 0xAA, 0xA2, 0x18, 0xF1, 0x50, 0x57, 0xF1, 0xDC, 0xB8, 0x24, 0xA2, 0x14,
0x98, 0x0B, 0x74, 0x46, 0x88, 0xA0, 0x88, 0x8A, 0x02, 0x97, 0xFA, 0x7D, 0xC5, 0xE1, 0xEA, 0xD8,
0xCA, 0x12, 0x91, 0xDB, 0x22, 0x9C, 0x28, 0xEB, 0x86, 0x78, 0xBC, 0xE8, 0x00, 0x82, 0x2C, 0x07,
0x22, 0x8F, 0x41, 0x6A, 0xE4, 0x9D, 0x21, 0x8E, 0x5D, 0xA2, 0xF2, 0xD1, 0xA8, 0xA2, 0x7D, 0xC1,
0x9A, 0xDF, 0x66, 0x8A, 0x74, 0x62, 0x89, 0x99, 0xD2, 0x22, 0xB4, 0x01, 0x59, 0xD8, 0x07, 0x6F,
0xAF, 0xBB, 0x8C, 0x5E, 0xDB, 0xA3, 0x7E, 0x30, 0x7C, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1D, 0x13,
0x01, 0x01, 0xFF, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01, 0x00, 0x30, 0x0E, 0x06,
0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x16, 0x06,
0x06, 0x67, 0x81, 0x05, 0x05, 0x04, 0x04, 0x04, 0x0C, 0x30, 0x0A, 0x04, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14,
0x21, 0xEE, 0xEF, 0x9A, 0x4C, 0x61, 0xD4, 0xB9, 0xE3, 0xD9, 0x4B, 0xEA, 0x46, 0xF9, 0xA1, 0x2A,
0xC6, 0x88, 0x7C, 0xE2, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
0x14, 0x42, 0x4F, 0x3A, 0xC7, 0x45, 0xDD, 0xBD, 0x50, 0x15, 0x05, 0x7F, 0x5B, 0xF8, 0x3E, 0x9C,
0xD6, 0x48, 0x10, 0xB0, 0x41,
];
const FAKE_LDEV_TBS: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/ldev_tbs.der"));
const FAKE_LDEV_PUB_KEY: Ecc384PubKey = Ecc384PubKey {
x: Array4xN([
0x842C00AF, 0x05ACCCEB, 0x14514E2D, 0x37B0C3AA, 0xA218F150, 0x57F1DCB8, 0x24A21498,
Expand All @@ -87,14 +52,8 @@ const FAKE_LDEV_PUB_KEY: Ecc384PubKey = Ecc384PubKey {
]),
};
const FAKE_LDEV_SIG: Ecc384Signature = Ecc384Signature {
r: Array4xN([
0x0C1B9586, 0x1ADA0DF5, 0x72438E88, 0xB23DDD5B, 0x2C24C974, 0xDF359988, 0xCC54E39E,
0x3145635A, 0x94E3D819, 0x6B49164C, 0xAD991714, 0xC2B18892,
]),
s: Array4xN([
0x4BEDF2A7, 0xDEC94059, 0x64ADF494, 0x9819FADE, 0x2CD785CD, 0x0307078F, 0x74EA4E5C,
0xDDF8D1FA, 0xE5380507, 0xAB098713, 0x44CA288F, 0xA6961532,
]),
r: Array4xN(include!(concat!(env!("OUT_DIR"), "/ldev_sig_r_words.txt"))),
s: Array4xN(include!(concat!(env!("OUT_DIR"), "/ldev_sig_s_words.txt"))),
};

const FAKE_FMC_ALIAS_TBS: [u8; 745] = [
Expand Down
25 changes: 24 additions & 1 deletion runtime/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ use openssl::{
ecdsa::EcdsaSig,
nid::Nid,
pkey::PKey,
x509::X509,
stack::Stack,
x509::{
store::X509StoreBuilder, verify::X509VerifyFlags, X509StoreContext, X509VerifyResult, X509,
},
};
use zerocopy::{AsBytes, FromBytes, LayoutVerified};

Expand Down Expand Up @@ -158,6 +161,26 @@ fn test_certs() {
.unwrap(),
core::cmp::Ordering::Equal
);

// Verify full cert chain
let mut roots_bldr = X509StoreBuilder::new().unwrap();
roots_bldr.add_cert(ldev_cert).unwrap();
roots_bldr
.set_flags(X509VerifyFlags::X509_STRICT | X509VerifyFlags::PARTIAL_CHAIN)
.unwrap();
let roots = roots_bldr.build();
let mut cert_store = X509StoreContext::new().unwrap();
let mut chain = Stack::new().unwrap();
chain.push(fmc_cert).unwrap();
cert_store
.init(&roots, &rt_cert, &chain, |c| {
let success = c.verify_cert().unwrap();
assert_eq!(c.error(), X509VerifyResult::OK);
assert!(success);

Ok(())
})
.unwrap();
}

#[test]
Expand Down
Binary file modified test/tests/smoke_testdata/idevid_csr.der
Binary file not shown.
14 changes: 7 additions & 7 deletions test/tests/smoke_testdata/idevid_csr.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ Certificate Request:
Attributes:
Requested Extensions:
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
CA:TRUE, pathlen:5
X509v3 Key Usage: critical
Certificate Sign
2.23.133.5.4.4:
0
..........
Signature Algorithm: ecdsa-with-SHA384
30:64:02:30:29:96:24:94:0f:8b:8f:77:a5:27:42:21:51:bd:
66:fd:fc:93:04:e7:c0:57:20:df:15:bf:c2:e0:32:23:21:be:
35:e7:2c:8f:ac:4e:05:f0:fe:bc:34:a4:a5:47:7a:79:02:30:
0a:87:63:da:eb:fd:9b:07:d8:87:3a:dc:88:0d:66:b4:b6:4d:
f7:d7:87:b7:48:46:e1:4e:c2:c6:5f:55:7d:ee:3b:68:26:bb:
38:6c:0f:e8:71:91:d0:f9:03:c3:0c:0d
30:66:02:31:00:c5:13:78:46:d9:38:27:82:67:db:f2:23:6a:
02:4b:a7:6d:19:21:57:e7:04:50:a1:08:6d:f2:ba:66:d7:7f:
e6:1e:01:28:93:6e:82:e3:0c:1f:f9:12:33:59:61:23:ce:02:
31:00:ae:1e:39:b8:21:79:da:c8:4c:a1:92:4d:06:79:d4:8d:
74:34:84:5c:ed:0d:a7:45:58:79:f7:45:21:4a:60:dc:2a:48:
21:cc:5f:f7:10:f8:f4:a6:f6:bc:05:31:ea:6a
Binary file modified test/tests/smoke_testdata/ldevid_cert.der
Binary file not shown.
14 changes: 7 additions & 7 deletions test/tests/smoke_testdata/ldevid_cert.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Certificate:
NIST CURVE: P-384
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
CA:TRUE, pathlen:4
X509v3 Key Usage: critical
Certificate Sign
2.23.133.5.4.4:
Expand All @@ -36,9 +36,9 @@ Certificate:
keyid:42:4F:3A:C7:45:DD:BD:50:15:05:7F:5B:F8:3E:9C:D6:48:10:B0:41

Signature Algorithm: ecdsa-with-SHA384
30:64:02:30:0c:1b:95:86:1a:da:0d:f5:72:43:8e:88:b2:3d:
dd:5b:2c:24:c9:74:df:35:99:88:cc:54:e3:9e:31:45:63:5a:
94:e3:d8:19:6b:49:16:4c:ad:99:17:14:c2:b1:88:92:02:30:
4b:ed:f2:a7:de:c9:40:59:64:ad:f4:94:98:19:fa:de:2c:d7:
85:cd:03:07:07:8f:74:ea:4e:5c:dd:f8:d1:fa:e5:38:05:07:
ab:09:87:13:44:ca:28:8f:a6:96:15:32
30:65:02:31:00:ec:d3:24:ac:d4:eb:9c:9f:8f:30:87:c3:92:
22:71:4d:27:a7:44:dd:13:9c:b4:19:57:47:bb:c9:6c:23:84:
fb:74:ba:d9:10:01:dc:73:e5:56:a1:20:b3:40:18:4f:d9:02:
30:0c:98:bb:ca:0b:39:f5:bb:4b:00:19:5d:8a:d6:9b:92:0f:
9f:d9:22:ae:1d:7f:ff:81:25:bc:70:2a:7e:77:29:e9:1f:cc:
ae:7b:07:15:c5:7a:69:0f:1a:3b:75:12:c9
10 changes: 5 additions & 5 deletions x509/build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn gen_init_devid_csr(out_dir: &str) {
let mut usage = KeyUsage::default();
usage.set_key_cert_sign(true);
let bldr = csr::CsrTemplateBuilder::<EcdsaSha384Algo>::new()
.add_basic_constraints_ext(true, 0)
.add_basic_constraints_ext(true, 5)
.add_key_usage_ext(usage)
.add_ueid_ext(&[0xFF; 8]);
let template = bldr.tbs_template("Caliptra IDevID");
Expand All @@ -52,7 +52,7 @@ fn gen_local_devid_cert(out_dir: &str) {
let mut usage = KeyUsage::default();
usage.set_key_cert_sign(true);
let bldr = cert::CertTemplateBuilder::<EcdsaSha384Algo>::new()
.add_basic_constraints_ext(true, 0)
.add_basic_constraints_ext(true, 4)
.add_key_usage_ext(usage)
.add_ueid_ext(&[0xFF; 8]);
let template = bldr.tbs_template("Caliptra LDevID", "Caliptra IDevID");
Expand All @@ -63,7 +63,7 @@ fn gen_fmc_alias_cert(out_dir: &str) {
let mut usage = KeyUsage::default();
usage.set_key_cert_sign(true);
let bldr = cert::CertTemplateBuilder::<EcdsaSha384Algo>::new()
.add_basic_constraints_ext(true, 0)
.add_basic_constraints_ext(true, 3)
.add_key_usage_ext(usage)
.add_ueid_ext(&[0xFF; 8])
.add_fmc_dice_tcb_info_ext(
Expand Down Expand Up @@ -95,8 +95,8 @@ fn gen_rt_alias_cert(out_dir: &str) {
// Add DigitalSignature to allow signing of firmware
usage.set_digital_signature(true);
let bldr = cert::CertTemplateBuilder::<EcdsaSha384Algo>::new()
// Basic Constraints : CA = true, PathLen = 1
.add_basic_constraints_ext(true, 1)
// Basic Constraints : CA = true, PathLen = 2
.add_basic_constraints_ext(true, 2)
.add_key_usage_ext(usage)
.add_ueid_ext(&[0xFF; 8])
.add_rt_dice_tcb_info_ext(&[FwidParam {
Expand Down

0 comments on commit 69c4614

Please sign in to comment.