Skip to content

Commit fd20945

Browse files
committed
dice-mfg-msgs: Impliment PlatformId::TryFrom<&PkiPath>
This is useful for pulling the PlatformId out of the cert chain produced by the RoT.
1 parent b111c7c commit fd20945

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dice-mfg-msgs/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ version = "0.2.1"
44
edition = "2021"
55

66
[dependencies]
7+
const-oid = { workspace = true, optional = true }
78
corncobs.workspace = true
89
hubpack.workspace = true
910
serde = { workspace = true, features = ["derive"] }
1011
serde-big-array.workspace = true
1112
thiserror = { workspace = true, optional = true }
13+
x509-cert = { workspace = true, optional = true }
1214
zerocopy.workspace = true
1315

1416
[features]
15-
std = ["thiserror"]
17+
std = ["const-oid/db", "thiserror", "x509-cert"]

dice-mfg-msgs/src/lib.rs

+83
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,20 @@
44

55
#![cfg_attr(not(any(test, feature = "std")), no_std)]
66

7+
#[cfg(feature = "std")]
8+
use const_oid::db::rfc4519::{COMMON_NAME, COUNTRY_NAME, ORGANIZATION_NAME};
79
use core::fmt;
810
use hubpack::SerializedSize;
911
use serde::{Deserialize, Serialize};
1012
use serde_big_array::BigArray;
13+
#[cfg(feature = "std")]
14+
use x509_cert::{
15+
der::{
16+
asn1::{PrintableString, Utf8StringRef},
17+
Error as DerError,
18+
},
19+
PkiPath,
20+
};
1121

1222
pub type MessageHash = [u8; 32];
1323
pub const NULL_HASH: MessageHash = [0u8; 32];
@@ -262,6 +272,79 @@ impl TryFrom<&[u8]> for PlatformId {
262272
}
263273
}
264274

275+
#[cfg(feature = "std")]
276+
#[cfg_attr(any(test, feature = "std"), derive(thiserror::Error))]
277+
#[derive(Debug)]
278+
pub enum PlatformIdPkiPathError {
279+
#[error("Failed to decode CountryName")]
280+
CountryNameDecode(DerError),
281+
#[error("Expected CountryName \"US\", got {0}")]
282+
InvalidCountryName(String),
283+
#[error("Failed to decode OrganizationName")]
284+
OrganizationNameDecode(DerError),
285+
#[error("Expected CountryName \"US\", got {0}")]
286+
InvalidOrganizationName(String),
287+
#[error("Failed to decode OrganizationName")]
288+
CommonNameDecode(DerError),
289+
#[error("More than one PlatformId found in PkiPath")]
290+
MultiplePlatformIds,
291+
#[error("No PlatformId found in PkiPath")]
292+
NoPlatformId,
293+
}
294+
295+
#[cfg(feature = "std")]
296+
impl TryFrom<&PkiPath> for PlatformId {
297+
type Error = PlatformIdPkiPathError;
298+
// Find the PlatformId in the provided cert chain. This value is stored in
299+
// cert's `Subject` field. The Subject field C / Country and O /
300+
// Organization must always be'US' and 'Oxide Computer Company'
301+
// respectively. The PlatformId string is stored in the Subject CN /
302+
// commonName.
303+
fn try_from(pki_path: &PkiPath) -> Result<Self, Self::Error> {
304+
let mut platform_id: Option<PlatformId> = None;
305+
for cert in pki_path {
306+
for elm in &cert.tbs_certificate.subject.0 {
307+
for atav in elm.0.iter() {
308+
if atav.oid == COUNTRY_NAME {
309+
let country = PrintableString::try_from(&atav.value)
310+
.map_err(Self::Error::CountryNameDecode)?;
311+
let country: &str = country.as_ref();
312+
if country != "US" {
313+
return Err(Self::Error::InvalidCountryName(
314+
country.to_string(),
315+
));
316+
}
317+
} else if atav.oid == ORGANIZATION_NAME {
318+
let organization = Utf8StringRef::try_from(&atav.value)
319+
.map_err(|e| {
320+
Self::Error::OrganizationNameDecode(e)
321+
})?;
322+
let organization: &str = organization.as_ref();
323+
if organization != "Oxide Computer Company" {
324+
return Err(Self::Error::InvalidOrganizationName(
325+
organization.to_string(),
326+
));
327+
}
328+
} else if atav.oid == COMMON_NAME {
329+
let common = Utf8StringRef::try_from(&atav.value)
330+
.map_err(Self::Error::CommonNameDecode)?;
331+
let common: &str = common.as_ref();
332+
if let Ok(id) = PlatformId::try_from(common) {
333+
if platform_id.is_none() {
334+
platform_id = Some(id);
335+
} else {
336+
return Err(Self::Error::MultiplePlatformIds);
337+
}
338+
}
339+
}
340+
}
341+
}
342+
}
343+
344+
platform_id.ok_or(Self::Error::NoPlatformId)
345+
}
346+
}
347+
265348
impl PlatformId {
266349
pub fn as_bytes(&self) -> &[u8] {
267350
match &self.0[..PREFIX_LEN] {

0 commit comments

Comments
 (0)