use alloc::vec;
use crate::{
builder::{BuilderProfile, Result},
certificate::TbsCertificate,
ext::{
Extension, ToExtension,
pkix::{
AuthorityKeyIdentifier, KeyUsage, KeyUsages, SubjectAltName,
name::{GeneralName, GeneralNames, HardwareModuleName, OtherName},
},
},
name::Name,
};
use der::{ErrorKind, asn1::OctetString};
use spki::{ObjectIdentifier, SubjectPublicKeyInfoRef};
#[allow(missing_docs)]
pub mod tcgtpm {
use const_oid::ObjectIdentifier;
pub const TCG_SV_TPM_12: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.23.133.1.0");
pub const TCG_SV_TPM_20: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.23.133.1.2");
}
pub struct DevId {
pub issuer: Name,
subject: Name,
subject_alt_name: Option<GeneralNames>,
}
impl DevId {
pub fn new(issuer: Name, subject: Name, alt_names: Option<GeneralNames>) -> Result<Self> {
if let Some(ref alt_names) = alt_names {
let mut found = false;
for gn in alt_names {
match gn {
GeneralName::OtherName(on)
if HardwareModuleName::from_other_name(on)?.is_some() =>
{
found = true;
break;
}
_ => {}
}
}
if !found {
return Err(der::Error::from(ErrorKind::Failed).into());
}
}
Ok(Self {
issuer,
subject,
subject_alt_name: alt_names,
})
}
pub fn idevid_tpm(
issuer: Name,
subject: Name,
hw_type: TpmVersion,
serial_number: OctetString,
) -> Result<Self> {
let hardware_module_name = HardwareModuleName {
hw_type: hw_type.to_oid(),
hw_serial_num: serial_number,
};
let alt_names = vec![GeneralName::OtherName(OtherName::try_from(
&hardware_module_name,
)?)];
Ok(Self {
issuer,
subject,
subject_alt_name: Some(alt_names),
})
}
}
impl BuilderProfile for DevId {
fn get_issuer(&self, _subject: &Name) -> Name {
self.issuer.clone()
}
fn get_subject(&self) -> Name {
self.subject.clone()
}
fn build_extensions(
&self,
_spk: SubjectPublicKeyInfoRef<'_>,
issuer_spk: SubjectPublicKeyInfoRef<'_>,
tbs: &TbsCertificate,
) -> Result<vec::Vec<Extension>> {
let mut extensions: vec::Vec<Extension> = vec::Vec::new();
extensions.push(
AuthorityKeyIdentifier::try_from(issuer_spk.clone())?
.to_extension(&tbs.subject, &extensions)?,
);
let key_usage = KeyUsages::DigitalSignature.into();
extensions.push(KeyUsage(key_usage).to_extension(&tbs.subject, &extensions)?);
if let Some(san) = &self.subject_alt_name {
extensions.push(SubjectAltName(san.clone()).to_extension(&tbs.subject, &extensions)?);
}
Ok(extensions)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TpmVersion {
Tpm12,
Tpm20,
#[cfg(feature = "hazmat")]
Other(ObjectIdentifier),
}
impl TpmVersion {
fn to_oid(&self) -> ObjectIdentifier {
match self {
Self::Tpm12 => tcgtpm::TCG_SV_TPM_12,
Self::Tpm20 => tcgtpm::TCG_SV_TPM_20,
#[cfg(feature = "hazmat")]
Self::Other(o) => *o,
}
}
}