-
Notifications
You must be signed in to change notification settings - Fork 6
C-FFI Support for SD Create Backup and Reseal API #576
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rajesh-gali
wants to merge
8
commits into
main
Choose a base branch
from
user/rajeshgali/tbor-sd-backup-cffi
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
dc63ab9
wip: sd create remote backup host layer (part_info, masked-blob key r…
e7aa60d
create backup and reseal c-ffi
8d8ae8a
fixed cert chain ordering commens
e1ec246
Merge branch 'main' into user/rajeshgali/tbor-sd-backup-cffi
141fe49
addressed review comment
b123c42
more review comments
68a40f5
added alignment check for algo params
6e766c0
review
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| //! Out-of-band SGL descriptor packing shared by TBOR commands that ship | ||
| //! DER certificate chains / reports out of band (`PartFinal`, the SD | ||
| //! backup family). | ||
| //! | ||
| //! Each item ships as its own OOB SGL Data Block; the firmware locates it | ||
| //! by the descriptor's `index` (its position in the shared `oob` item | ||
| //! list) and reads `length` bytes from it. | ||
|
|
||
| use azihsm_ddi_tbor_types::*; | ||
|
|
||
| use super::*; | ||
|
|
||
| /// Appends a certificate chain's DER bytes to `oob`, returning the | ||
| /// matching `(index, length)` descriptors. Rejects an empty chain, a | ||
| /// chain longer than `max_certs`, an empty (zero-length) cert, or a cert | ||
| /// whose length overflows the 16-bit descriptor field. | ||
| pub(crate) fn push_cert_chain<'a>( | ||
| chain: &'a [HsmCert<'a>], | ||
| oob: &mut Vec<&'a [u8]>, | ||
| max_certs: usize, | ||
| ) -> HsmResult<Vec<CertDescriptor>> { | ||
| // Firmware evidence verification rejects an empty chain as InvalidArg; | ||
| // fail fast rather than round-trip a guaranteed rejection. | ||
| if chain.is_empty() || chain.len() > max_certs { | ||
| return Err(HsmError::InvalidArgument); | ||
| } | ||
| let mut descriptors = Vec::with_capacity(chain.len()); | ||
| for cert in chain { | ||
| let der = cert.cert; | ||
| if der.is_empty() || der.len() > u16::MAX as usize { | ||
| return Err(HsmError::InvalidArgument); | ||
| } | ||
| // Descriptor index = position in the shared OOB list (must fit u8). | ||
| let index = u8::try_from(oob.len()).map_err(|_| HsmError::InvalidArgument)?; | ||
| descriptors.push(CertDescriptor { | ||
| index, | ||
| length: tbor_int::U16::new(der.len() as u16), | ||
| }); | ||
| oob.push(der); | ||
| } | ||
| Ok(descriptors) | ||
| } | ||
|
|
||
| /// Appends a COSE_Sign1 report DER to `oob`, returning its descriptor. | ||
| /// Rejects an empty report (firmware verification rejects `report_len == | ||
| /// 0` as InvalidArg) or one exceeding the 16-bit length. | ||
| pub(crate) fn push_report<'a>( | ||
| report: &'a [u8], | ||
| oob: &mut Vec<&'a [u8]>, | ||
| ) -> HsmResult<ReportDescriptor> { | ||
| if report.is_empty() || report.len() > u16::MAX as usize { | ||
| return Err(HsmError::InvalidArgument); | ||
| } | ||
| let index = u8::try_from(oob.len()).map_err(|_| HsmError::InvalidArgument)?; | ||
| let descriptor = ReportDescriptor { | ||
| index, | ||
| length: tbor_int::U16::new(report.len() as u16), | ||
| }; | ||
| oob.push(report); | ||
| Ok(descriptor) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| //! `SdCreateRemoteBackup` (opcode `0x0A`) over the TBOR transport at the | ||
| //! DDI layer. | ||
| //! | ||
| //! Creates a new security domain from a caller-supplied unified | ||
| //! `PartPolicy`, returning the remote partition-owner-key backup together | ||
| //! with the device-local partition-owner-key and security-domain | ||
| //! masking-key backups. Runs **inside an already-open session**; the | ||
| //! request carries the active session id, which the firmware dispatcher | ||
| //! cross-checks against the SQE-carried session id. Attestation evidence | ||
| //! travels out of band (see [`super::sd_evidence`]). | ||
|
|
||
| use azihsm_ddi_tbor_types::*; | ||
|
|
||
| use super::*; | ||
|
|
||
| /// Converts the wire `SdCreateRemoteBackup` response into the owned | ||
| /// API-layer [`HsmSdRemoteBackupResult`]. | ||
| impl From<TborSdCreateRemoteBackupResp> for HsmSdRemoteBackupResult { | ||
| fn from(resp: TborSdCreateRemoteBackupResp) -> Self { | ||
| Self { | ||
| pok_remote_backup: resp.pok_remote_backup.to_vec(), | ||
| pok_local_backup: resp.pok_local_backup.to_vec(), | ||
| sd_mk_backup: resp.sd_mk_backup.to_vec(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Issue `SdCreateRemoteBackup` (opcode `0x0A`) on the active session. | ||
| /// | ||
| /// Creates a new security domain from the caller-supplied unified | ||
| /// `policy`, using the sender's masked sealing key and the receiver's | ||
| /// attestation evidence, and returns the remote backup together with the | ||
| /// device-local backups. | ||
| /// | ||
| /// # Arguments | ||
| /// | ||
| /// * `partition` - The HSM partition handle. | ||
| /// * `session_id` - The active session id this request binds to. | ||
| /// * `masked_sealing_key` - The sender's masked SD-sealing key (from | ||
| /// `SdSealingKeyGen`), exactly [`MASKED_SEALING_KEY_LEN`] bytes. | ||
| /// * `receiver_evidence` - Receiver attestation evidence (cert chains and | ||
| /// report), transmitted out of band. | ||
| /// * `policy` - Unified [`PartPolicy`] image ([`PART_POLICY_LEN`] bytes). | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns [`HsmError::InvalidArgument`] for a wrong-length | ||
| /// `masked_sealing_key` or a malformed `policy`, and surfaces DDI/device | ||
| /// failures from the round-trip. | ||
| pub(crate) fn sd_create_remote_backup_ex( | ||
| partition: &HsmPartition, | ||
| session_id: u16, | ||
| masked_sealing_key: &[u8], | ||
| receiver_evidence: &HsmSdEvidence<'_>, | ||
| policy: &[u8], | ||
| ) -> HsmResult<HsmSdRemoteBackupResult> { | ||
| // Exact-length array conversion enforces MASKED_SEALING_KEY_LEN. | ||
| let masked_sealing_key: [u8; MASKED_SEALING_KEY_LEN] = masked_sealing_key | ||
| .try_into() | ||
| .map_err(|_| HsmError::InvalidArgument)?; | ||
| let policy = decode_policy(policy)?; | ||
|
|
||
| // Flatten the receiver evidence into descriptors + shared OOB items. | ||
| let mut oob: Vec<&[u8]> = Vec::new(); | ||
| let receiver = push_evidence(receiver_evidence, &mut oob)?; | ||
|
|
||
| let req = TborSdCreateRemoteBackupReq { | ||
| session_id, | ||
| masked_sealing_key, | ||
| receiver_mfgr_cert_chain: receiver.mfgr, | ||
| receiver_owner_cert_chain: receiver.owner, | ||
| receiver_part_owner_cert_chain: receiver.part_owner, | ||
| receiver_report: receiver.report, | ||
| policy, | ||
| }; | ||
|
|
||
| let inner = partition.inner().read(); | ||
| let dev = inner.dev(); | ||
| let mut cookie = None; | ||
| let oob_items = (!oob.is_empty()).then_some(oob.as_slice()); | ||
| dev.exec_op_tbor(&req, oob_items, &mut cookie) | ||
| .map(HsmSdRemoteBackupResult::from) | ||
| .map_err(HsmError::from) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| //! Shared helpers for the security-domain backup commands | ||
| //! (`SdCreateRemoteBackup`, `SdResealRemoteBackup`). | ||
| //! | ||
| //! # Out-of-band evidence | ||
| //! | ||
| //! Bulk attestation evidence (DER cert chains and a COSE_Sign1 report) | ||
| //! travels out of band: each [`HsmSdEvidence`] is flattened into | ||
| //! `(index, length)` descriptors (via [`super::descriptor_utils`]) and its | ||
| //! DER bytes | ||
| //! are shipped as `oob_items`, mirroring the `PartFinal` cert-chain | ||
| //! transport. | ||
|
|
||
| use azihsm_ddi_tbor_types::*; | ||
|
|
||
| use super::*; | ||
|
|
||
| /// Decodes a caller-supplied unified `PartPolicy` image | ||
| /// ([`PART_POLICY_LEN`] bytes), failing fast with | ||
| /// [`HsmError::InvalidArgument`] on a wrong length or malformed image. | ||
| pub(crate) fn decode_policy(policy: &[u8]) -> HsmResult<PartPolicy> { | ||
| if policy.len() != PART_POLICY_LEN { | ||
| return Err(HsmError::InvalidArgument); | ||
| } | ||
| <PartPolicy as zerocopy::TryFromBytes>::try_read_from_bytes(policy) | ||
| .map_err(|_| HsmError::InvalidArgument) | ||
| } | ||
|
|
||
| /// Wire descriptors for one attestation party: the three cert-chain | ||
| /// lists plus the report descriptor. Produced by [`push_evidence`]. | ||
| pub(crate) struct EvidenceDescriptors { | ||
| pub(crate) mfgr: Vec<CertDescriptor>, | ||
| pub(crate) owner: Vec<CertDescriptor>, | ||
| pub(crate) part_owner: Vec<CertDescriptor>, | ||
| pub(crate) report: ReportDescriptor, | ||
| } | ||
|
|
||
| /// Flattens one [`HsmSdEvidence`] party into its wire descriptors, | ||
| /// appending all referenced DER bytes (the three cert chains, then the | ||
| /// report) to the shared `oob` list so their descriptor indices are | ||
| /// contiguous. | ||
| pub(crate) fn push_evidence<'a>( | ||
| evidence: &HsmSdEvidence<'a>, | ||
| oob: &mut Vec<&'a [u8]>, | ||
| ) -> HsmResult<EvidenceDescriptors> { | ||
| Ok(EvidenceDescriptors { | ||
| mfgr: push_cert_chain(evidence.mfgr_cert_chain, oob, EVIDENCE_CHAIN_MAX_CERTS)?, | ||
| owner: push_cert_chain(evidence.owner_cert_chain, oob, EVIDENCE_CHAIN_MAX_CERTS)?, | ||
| part_owner: push_cert_chain( | ||
| evidence.part_owner_cert_chain, | ||
| oob, | ||
| EVIDENCE_CHAIN_MAX_CERTS, | ||
| )?, | ||
| report: push_report(evidence.report, oob)?, | ||
| }) | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.