chipsalliance / caliptra-sw Goto Github PK
View Code? Open in Web Editor NEWCaliptra software (ROM, FMC, runtime firmware), and libraries/tools needed to build and test
License: Apache License 2.0
Caliptra software (ROM, FMC, runtime firmware), and libraries/tools needed to build and test
License: Apache License 2.0
Placeholder until we get more clarity from FIPS certifiability assessment
Will tag spec issue: chipsalliance/Caliptra#42. Tagging as 0p8 as something will need to pair up with HW
EnvCell::map allows multiple aliasing &mut references to the same memory location to be created from a safe module, which is unsound.
#[test]
fn unsound_envcell() {
let cell: EnvCell<u32> = EnvCell::new(42);
cell.map(|ref0: &mut u32| {
cell.map(|ref1: &mut u32| {
// Soundness violation: ref0 and ref1 both point to the same memory location
assert_eq!(ref0 as *mut u32, ref1 as *mut u32);
})
});
}
$ cargo +nightly miri test -p caliptra-rom unsound_envcell
unning 1 test
test env_cell::test::unsound_envcell ... error: Undefined Behavior: not granting access to tag <184548> because that would remove [Unique for <184541>] which is strongly protected because it is an argument of call 51579
--> rom/dev/src/env_cell.rs:39:26
|
39 | closure(unsafe { &mut *self.val.get() })
| ^^^^^^^^^^^^^^^^^^^^ not granting access to tag <184548> because that would remove [Unique for <184541>] which is strongly protected because it is an argument of call 51579
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <184548> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> rom/dev/src/env_cell.rs:39:32
|
39 | closure(unsafe { &mut *self.val.get() })
| ^^^^^^^^^^^^^^
help: <184541> is this argument
--> rom/dev/src/env_cell.rs:35:29
|
35 | pub fn map<F, R>(&self, closure: F) -> R
| ^^^^^^^
= note: BACKTRACE (of the first span):
= note: inside `env_cell::EnvCell::<u32>::map::<[closure@rom/dev/src/env_cell.rs:61:22: 61:38], ()>` at rom/dev/src/env_cell.rs:39:26: 39:46
note: inside closure
--> rom/dev/src/env_cell.rs:61:13
|
61 | / cell.map(|ref1: &mut u32| {
62 | | // Soundness violation: ref0 and ref1 both point to the same memory location
63 | | assert_eq!(ref0 as *mut u32, ref1 as *mut u32);
64 | | })
| |______________^
note: inside `env_cell::EnvCell::<u32>::map::<[closure@rom/dev/src/env_cell.rs:60:18: 60:34], ()>`
--> rom/dev/src/env_cell.rs:39:9
|
39 | closure(unsafe { &mut *self.val.get() })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `env_cell::test::unsound_envcell`
--> rom/dev/src/env_cell.rs:60:9
|
60 | / cell.map(|ref0: &mut u32| {
61 | | cell.map(|ref1: &mut u32| {
62 | | // Soundness violation: ref0 and ref1 both point to the same memory location
63 | | assert_eq!(ref0 as *mut u32, ref1 as *mut u32);
64 | | })
65 | | });
| |__________^
note: inside closure
--> rom/dev/src/env_cell.rs:58:26
|
57 | #[test]
| ------- in this procedural macro expansion
58 | fn unsound_envcell() {
| ^
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
(Starting in RTL repo, but outcome could lead to transfer to SW repo)
Warm reset cannot be pre-conditioned by Caliptra SW. Warm Reset does not clear RAMs, reset Key Vault, or reset Data Vault. Caliptra spec does not bound when a Warm Reset can occur. Therefore a Warm Reset could leave Caliptra in an undefined state.
One goal of Caliptra is to provide a firmware signing scheme for defending against attacks from quantum computers. Currently, only stateful PQC signing algorithms are approved by NIST. Caliptra has chosen to use LMS for firmware signing. Caliptra also supports ECDSA P-384 signing schemes. We need to decide which of these verification schemes will be used in which cases.
I propose that Caliptra should support multiple possible modes of signature verification.
The key manifest may contain all of
Assuming P-384 ECDSA keys and SHA384 LMS keys, at most, this adds 192 bytes compared to only-ECDSA or only-LMS.
This manifest is:
A firmware image header may contain all of
In this case, LMS signatures are much larger than ECC signatures. The overhead of including both (instead of just LMS) is minimal.
Which signatures are enforced by ROM needs to be configurable because LMS signers may not be ready until after tape-out. A public key in can be included in the fused manifest, but LMS signatures may not be available to sign images until some later time.
Note: If a manufacturer ever wants to support hybrid signing, both the ECDSA and LMS public keys must be present in the fused manifest at tape-out.
I propose a single configuration fuse bit:
If fuse is 0, use Mode 1
If fuse is 1, use Mode 2
Notably, once Caliptra is fused to do LMS verification, it cannot be fused to stop doing LMS.
Update documentation and FHT implementation with correct definitions for indexing into the Key Vault and Data Vault
Material stashed includes ROM patches, SoC FMC
From what I can tell, Caliptra 32-bit error codes are intended to be an 8-bit "component id" in high bits and a 24-bit "error code" in the low bits.
caliptra-sw/rom/dev/src/error.rs
Line 42 in 1b4af7a
Unfortunately, some of the component ids overflow 8 bits:
caliptra-sw/rom/dev/src/error.rs
Lines 15 to 28 in 1b4af7a
#[test]
fn test_error_value() {
let error_code: u32 = GlobalErr::Exception.into();
// Would be 0x1_0300_0002 without overflow
assert_eq!(error_code, 0x0300_0002);
}
This results in a error-space collision:
#[test]
fn test_error_value() {
let error_code: u32 = Sha384Err::ReadDataKvWrite.into();
// Collides with GlobalErr::Exception
assert_eq!(error_code, 0x0300_0002);
}
The address of an entry stored in the data vault is a pair (entry_type, entry_variant) , where entry type can be WarmResetEntry4, ColdResetEntry48, The entry type is an abstraction of the register type (sticky/non-sticky/scratch)
The entry type information is lost when conversion entry_type::entry_variant to u8 is performed forcing FMC to make assumptions about the entry type where the information is stored and defeating the purpose of a handoff table to decouple FMC and ROM.
Example :
rt_fw_load_addr_idx: WarmResetEntry4::RtLoadAddr.into(),
fmc_pub_key_x_dv_idx: ColdResetEntry48::FmcPubKeyX.into()
pub enum WarmResetEntry4 {
RtSvn = 0,
RtLoadAddr = 1,
RtEntryPoint = 2,
ManifestAddr = 3,
}
pub enum ColdResetEntry48 {
LDevDiceSigR = 0,
LDevDiceSigS = 1,
LDevDicePubKeyX = 2,
LDevDicePubKeyY = 3,
FmcDiceSigR = 4,
FmcDiceSigS = 5,
FmcPubKeyX = 6,
FmcPubKeyY = 7,
FmcTci = 8,
OwnerPubKeyHash = 9,
}
pub enum ColdResetEntry4 {
FmcSvn = 0,
FmcLoadAddr = 1,
FmcEntryPoint = 2,
VendorPubKeyIndex = 3,
}
specifically:
Implement code to locate and jump to Runtime module
Implement flow where
Per discussion in chipsalliance/Caliptra#25
"write a check that enforces that all release/ commits include a Release-Commit=$VALID_MAIN_SHA line in the description"
This may have utility value beyond the sw-emulator.
Originally posted by @rusty1968 in #142 (comment)
Currently, the following information is used to derive the FMC CDI:
However, only the following information is placed as evidence in the FMC alias certificate:
These two lists should be consistent. Any data used to derive the CDI, but not placed in the certificate over the resulting public key, cannot functionally be attested.
There are some options:
Option 1 presents a complication: we will need some way to ferry the new hash from ROM to FMC. For the other data in the certificate, this is currently done by way of Data Vault slots. However, we are currently at capacity for Data Vault slots. We would need to modify RTL to allocate at least one more digest-sized slot to hold this new information that FMC will need to reconstitute the certificate.
Alternatively, we could stash this data in a PCR. The issue there is that the data that FMC pulls out and places in the certificate will not be SHA384(...); rather, it will be SHA384(0x0000 || SHA384(...)) - the result of a hash extend.
One other option would be to expand the handoff table structure to include this new data. There is no special reason for the data to be locked away in a Data Vault slot. If it mutates after ROM uses it, the certificate that FMC reconstitutes will not have a valid signature.
Classify errors into fatal vs non-blocking
The drop trait implementation needs to be unwrap free. Currently the Mailbox Drop implementation is panicking due to unwraps. We should not be making any calls that results in unwraps to be called.
Close on format and implement FMC and runtime FW sides
FMC validates FHT marker field and that it has valid pointers and indices for the rest of the elements it requires to be passed from ROM
Problem statement: SoCs may have ROM patches and firmware that they need to boot before Caliptra firmware. Want to submit those measurements to Caliptra before execution.
Solution:
caliptra-sw/common/src/hand_off.rs
Line 102 in 80db9b8
Diagnostic and error reporting capability should reside in a common crate with all the caliptra error codes, that can be referenced from test cases and caliptra clients, including a Debug impl when compiled with the std feature.
The error namespace shall be partitioned to avoid collisions and enable better failure diagnostics
An enhancement to allow test cases to change (corrupt) DCCM locations to support error injection (e.g. corrupt the FHT or the manifest).
rom/dev/src/flow/cold_reset/crypto.rs
FMC specification is defining FHT.rt_fw_entry_point as the physical address of the entry point of Runtime FW Module in ICCM SRAM, however ROM is already making this information available in the data vault.
The proposal is to pass RT entry point field as the entry index instead of a physical address.
Dummy runtime module initially for use in development and testing of FMC but can be built out into the real runtime module as well.
Create basic test firmware to be used to simulate load and execution of FMC FW module.
Further down the road, this will also be used to unit-test sub-flows and functions as they are added.
The is currently an PR (#99) out for implementing an LMS driver. Some additional things we will need:
ROM:
Emulator:
Spec:
Runtime specification seems to call for a panic handler as part of its mailbox command error handling flow, but we have tests in place to detect if panic symbol is included .
A mailbox command can fail to complete in a couple ways
Hang/timeout which results in the watchdog firing
Unrecoverable panic
In both these cases, the panic handler will write diagnostic panic information to registers readable by the SoC, firmware will undergo impactless reset, and mailbox_data_avail will be asserted.
May choose to represent FMC+RT fw versions as hashes, rather than numerical values. This command should also include SVN information.
With the old RTL, no problem...
$ git checkout main
$ (cd hw-latest/caliptra-rtl/ && git log -2 --oneline)
6b69da9 (HEAD) Fix AHB multiplexing issue: #20
01fcfd1 Initial Pre0p8 release from dev-msft (#9)
$ export CXX="ccache g++"
$ cargo test --release --features=verilator -p caliptra-lib test_hmac384
<snip>
hmac384::test_kat... [ok]
hmac384::test_hmac0... [ok]
hmac384::test_hmac1... [ok]
test test_hmac384 has been running for over 60 seconds
hmac384::test_hmac3... [ok]
<snip>
With the new RTL...
$ git checkout rtl-2023-03-27
$ (cd hw-latest/caliptra-rtl/ && git log -8 --oneline)
cdd9afa (HEAD, ahb-mux-fix) Fix AHB multiplexing issue: #20
fa91d66 (main) Merge pull request #27 from chipsalliance/dev-integrate
f47d19d Sync from MSFT Internal repo w/ TRNG, HMAC SCA, PCR Hash/sign, Env Var rename (#21)
e5c1b48 Checking in a copy of the opentitan repository taken at (#22)
3678553 Adding verilator CI smoke test (#19)
b19f4ff Add Register docs links to README.md (#13)
01fcfd1 Initial Pre0p8 release from dev-msft (#9)
$ cargo test --release --features=verilator -p caliptra-lib test_hmac384
hmac384::test_kat... [ok]
hmac384::test_hmac0... [ok]
hmac384::test_hmac1... [ok]
test test_hmac384 has been running for over 60 seconds
hmac384::test_hmac3... [failed]
Error: panicked at 'assertion failed: `(left == right)`
left: `Array4xN([1097496930, 177872290, 3861325564, 3222974378, 3615216998, 3373329619, 1992284781, 2272737848, 311909870, 2326523809, 2038415403, 775445936])`,
right: `Array4xN([3806224643, 3931861133, 1050772493, 1774245656, 4173031246, 1110546316, 4049204051, 1657138985, 2965254665, 1955743625, 2383417612, 2640588215])`', drivers/test-fw/src/bin/hmac384_tests.rs:122:5
* TESTCASE FAILED
The test case does the following:
fn test_hmac3() {
//
// Step 1: Place a key in the key-vault.
//
let seed = [0u8; 48];
let mut key_usage = KeyUsage::default();
key_usage.set_hmac_key(true);
let key_out_1 = KeyWriteArgs {
id: KeyId::KeyId0,
usage: key_usage, // hmac_key
};
let result = Ecc384::default().key_pair(
Ecc384Seed::from(&Ecc384Scalar::from(seed)),
Ecc384PrivKeyOut::from(key_out_1),
);
assert!(result.is_ok());
//
// Step 2: Hash the data with the key from key-vault.
// Key is [0xc9, 0x8, 0x58, 0x5a, 0x48, 0x6c, 0x3b, 0x3d, 0x8b, 0xbe, 0x50, 0xeb, 0x7d, 0x2e, 0xb8, 0xa0,
// 0x3a, 0xa0, 0x4e, 0x3d, 0x8b, 0xde, 0x2c, 0x31, 0xa8, 0xa2, 0xa1, 0xe3, 0x34, 0x9d, 0xc2, 0x1c,
// 0xbb, 0xe6, 0xc9, 0xa, 0xe2, 0xf7, 0x49, 0x12, 0x88, 0x84, 0xb6, 0x22, 0xbb, 0x72, 0xb4, 0xc5,];
//
let data: [u8; 8] = [0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65];
let result: [u8; 48] = [
0xe2, 0xde, 0x61, 0x3, 0xea, 0x5b, 0x70, 0x8d, 0x3e, 0xa1, 0x84, 0xd, 0x69, 0xc0, 0xd7,
0x18, 0xf8, 0xbb, 0x67, 0x4e, 0x42, 0x31, 0x97, 0x8c, 0xf1, 0x59, 0xf3, 0x53, 0x62, 0xc5,
0xef, 0x29, 0xb0, 0xbe, 0x32, 0x9, 0x74, 0x92, 0x47, 0x89, 0x8e, 0x10, 0x11, 0xc, 0x9d,
0x64, 0x2d, 0xb7,
];
let mut out_tag = Array4x12::default();
let key = KeyReadArgs::new(KeyId::KeyId0);
let actual = Hmac384::default().hmac(key.into(), (&data).into(), (&mut out_tag).into());
assert!(actual.is_ok());
assert_eq!(out_tag, Array4x12::from(result));
}
It's not clear to me whether the test-case or the RTL is faulty.
Don't need to decide in this PR, but if something fails during boot we probably want to do one of
This is probably something to discuss with the group.
Originally posted by @jhand2 in #135 (comment)
Known Answer Tests as a pre-condition for FIPS certifiabilityu
FMC must:
Implementation should follow example of ROM implementation, as it may be possible to combine some of this code into common functions in the future.
Dependent on a complete TRNG gasket RTL integration
From https://github.com/chipsalliance/caliptra-rtl/blob/main/docs/Caliptra_Integration_Specification.pdf:
9.3 Sender Protocol
Sending data to the mailbox:
- Requester queries the mailbox by reading the LOCK control register.
- If LOCK returns 0, LOCK is granted and will be set to 1.
- If LOCK returns 1, MBOX is locked for another device.
- Requester writes the command to the COMMAND register.
- Requester writes the data length in bytes to the DLEN register.
- Requester writes data packets to the MBOX DATAIN register.
- Requester writes to the EXECUTE register.
- Requester reads the STATUS register. Status can return:
- CMD_BUSY - 2’b00 – Indicates the requested command is still in progress
- DATA_READY - 2’b01 – Indicates the return data is in the mailbox for requested command
- CMD_COMPLETE- 2’b10 – Indicates the successful completion of the requested command
- CMD_FAILURE- 2’b11 – Indicates the requested command failed
- Requester reads the response if DATA_READY was the status.
- Requester resets the EXECUTE register to release the lock.
9.4 Receiver Protocol
Upon receiving indication that mailbox has been populated, the appropriate device can read the
mailbox. This is indicated by a dedicated wire that is asserted when Caliptra populates the mailbox for SoC consumption.Receiving data from the mailbox:
- On mailbox_data_avail assertion, the receiver reads the COMMAND register.
- Receiver reads the DLEN register.
- Receiver reads the MBOX DATAOUT register.
- Continue reading MBOX DATAOUT register until DLEN bytes are read.
- If a response is required, receiver can populate the mailbox with the response by writing DATAIN
- Set the mailbox status register to hand control back to the sender to read the response
- The sender will reset the EXECUTE register after reading the response.
- This releases the LOCK on the mailbox.
See this code in the mailbox driver:
caliptra-sw/drivers/src/mailbox.rs
Lines 67 to 76 in 1b4af7a
This is incorrect. Nowhere in section 9.4 do the docs mention a receiver reading the status field, which is only used to notify the original sender (the SoC) of the result. The driver should not be looking at mbox.status().read().status()
, but instead mbox.status().read().mbox_fsm_ps() == MboxFsmE::MboxExecuteUc
, which becomes true after the SoC sets the execute bit. (The docs say to use the interrupt, but I can't find docs stating which interrupt line comes from the mailbox, and the fsm state field seems to work well enough).
Because of this mistake, tests pretending to be the SoC are setting the data-ready bit manually, which is also incorrect:
caliptra-sw/sw-emulator/app/src/main.rs
Lines 301 to 305 in 1b4af7a
caliptra-sw/hw-model/src/lib.rs
Lines 213 to 219 in 1b4af7a
All this has to be fixed, and the emulator needs to be modified to behave the same as the RTL.
NVIDIA uses an SoC C-model to do code development and validation for fullchip collateral. We would want to integrate a Caliptra model of the external registers https://ereg.caliptra.org for the boot process and the SoC ROM code to develop against.
@nstewart-amd had proposed a similar problem statement to @korran and @vsonims during December meet-up. Unclear whether there was a follow-up, so filing the ticket.
As per Caliptra top-level specification:
Current PCR : PCR3
journey PCR: PCR2
A discussion came up in #7 about whether Caliptra DPE and DICE certificates should expire. Opening this issue to have a longer discussion and unblock #7.
I think a few questions need answering:
Capturing some of that discussion:
From @Bryankel
In certificate-based cryptography, certificates have a validity period that manages the life cycle of the certificate. The validity period is important for PKI revocation to work effectively. The PKI CRL maintains a list of revoked certificates within a window of a given certificate validity period. In x509 PKI, the CRL is pruned based on this certificate validity sliding window. If certificates do not have a reasonable validity period will quickly become unmanageable at scale, as the CRL would grow indefinitely.
In having indefinite certificates it eliminates interoperability with most PKI systems and their revocation mechanisms. The alternative is every Caliptra needs to have a dedicated offline CA that can be revoked, this is heavy burden on PKI infra.
Some open questions if we did make certificates expire:
One possible mechanisms discussed in #7: Owner-signed blob in the firmware image with the expiration value.
For Caliptra, DICE and DPE provide the basis for attestation. This provides software oracle access to a signing key derived from measurements up-to and including that component. This is generally useful for signing attestations but has one limitation; to attest the whole SoC with DPE you would need to challenge all the leaf keys on the SoC and parse their certificates. This is prohibitively challenging for providing a single point for getting all the measurements for the SoC. To accomplish this, we propose the following.
In SoC integrations, we expect an SoC Manager to implement an SPDM Responder. SoC Manager firmware is measured into Caliptra DPE during SoC ROM boot. This provides SoC Manager with an identity that it cannot forge (SoC Manager Alias
).
It can populate SPDM measurement blocks by retrieving tagged measurements from DPE/Caliptra (see below).
DPE provides the following commands to help here:
During SoC boot/execution, any measurements made into DPE that the SoC manager wishes to report for whole-soc attestation will be tagged:
Any SoC entity can then retrieve these measurements (including both current and journey measurements).
SoC manager gets measurements from DPE unsigned and then reports them via SPDM. Why can't it lie?
This is because SoC Manager Alias Cert
contains SoC manager firmware measurements and roots back to Caliptra's DICE identity. A malicious SoC Manager reporting bad SPDM measurements can be found out when validating its Alias Certificate.
Any signing oracle Caliptra exposes should map to an industry standard API, which will ease integration with datacenter attestation flows and middleware routing protocols such as Redfish. As Caliptra Core does not expose an SPDM Responder, it is preferable for these measurements to be encapsulated within an SPDM message constructed by an SoC Manager, rather than encapsulated within a custom Caliptra-defined structure that does not map to any existing standard attestation protocol. Note also that DPE measurements form a tree structure, rather than a linear list of PCRs. Each integration will construct this tree in a different manner; Caliptra is agnostic as to the tree's structure. The mechanism proposed above enables an SoC Manager to present measurements from the tree in whatever manner makes the most sense for a given integration.
The Runtime Firmware specification should define usage of some shared Caliptra resources. In particular:
Main Caliptra spec says 128 bits, ROM spec says 64 bits
Created this issue to track open conversation in this PR: #8
jhand2 2 weeks ago
We probably need to reuse this key on impactless reset right? So to avoid rederiving the Private key probably need to cache in in keyvault and lock it. Not sure what the mechanisms are for locking/unlocking slots.
Member
Author
@FerralCoder FerralCoder 2 weeks ago
You may be right, I am waiting to see the final definition of the hardware capabilities before I add in more specific details about hitless update. This is captured as a "ToDo" item at the bottom of the doc.
Member
@JohnTraverAmd JohnTraverAmd last week
@jhand2 The KeyVault is not accessible by FW. The keys can be referenced/used by FW, but not read. When you say Locking, what do you want locked?
Member
@jhand2 jhand2 last week
I mean locking from use. We need to be able to use this key in FMC during impactless resets, but we don't want Runtime Firmware to be able to use it. Not sure if KeyVault can lock things from use until next impactless reset.
In theory you could just re-derive the key, but there might be FIPS concern there. Not sure.
Member
@Bryankel Bryankel last week
The current architecture preserves across resets. In the current architecture the ROM cannot rederive the FMC UDS, it must preserve it in the KV. The fused entropy that's the UDS is only transiently available on cold boot.
Member
@jhand2 jhand2 last week
If preserved in KV, can we prevent runtime firmware from using it?
Member
@Bryankel Bryankel last week
It gets locked by ROM
Member
@jhand2 jhand2 last week
Cool, just wanted to make sure we have a mechanism in hardware to lock/unlock.
Member
Author
@FerralCoder FerralCoder 18 hours ago
It needs to be locked by FMC, not ROM. Otherwise FMC will not be able to use it to certify RT
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.