x509_cert/builder/profile/devid.rs
1//! Profile for 802.1AR // Secure Device Identity certificates
2//!
3//! Specification can be found here:
4//! <https://ieeexplore.ieee.org/document/8423794>
5
6// NOTE(baloo): due to copyright issues, I am not going to
7// copy paste parts of spec relevant to the implementation.
8// Unlike other organizations, IEEE does not appear to grant a license for
9// reproduction in implementations.
10// There is a fair use exclusion to copyright, but I am not willing to
11// go to court to test waters.
12//
13// You, as a reader/reviewer, are expected to download a copy of the spec
14// yourself.
15
16use alloc::vec;
17
18use crate::{
19 builder::{BuilderProfile, Result},
20 certificate::TbsCertificate,
21 ext::{
22 Extension, ToExtension,
23 pkix::{
24 AuthorityKeyIdentifier, KeyUsage, KeyUsages, SubjectAltName,
25 name::{GeneralName, GeneralNames, HardwareModuleName, OtherName},
26 },
27 },
28 name::Name,
29};
30use der::{ErrorKind, asn1::OctetString};
31use spki::{ObjectIdentifier, SubjectPublicKeyInfoRef};
32
33// TODO(tarcieri): use this when `const-oid` has been bumped to v0.10.0-rc.0
34//use const_oid::db::tcgtpm;
35#[allow(missing_docs)]
36pub mod tcgtpm {
37 use const_oid::ObjectIdentifier;
38 pub const TCG_SV_TPM_12: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.23.133.1.0");
39 pub const TCG_SV_TPM_20: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.23.133.1.2");
40}
41
42/// DevID Certificate
43///
44/// See: section 8 DevID certificate fields and extensions
45pub struct DevId {
46 /// issuer Name,
47 /// represents the name signing the certificate
48 pub issuer: Name,
49
50 subject: Name,
51
52 subject_alt_name: Option<GeneralNames>,
53}
54
55impl DevId {
56 /// Create a new DevID
57 ///
58 /// Spec: 802.1AR Section 8.10.4 subjectAltName
59 /// Also documented in
60 /// <https://trustedcomputinggroup.org/wp-content/uploads/TPM-2p0-Keys-for-Device-Identity-and-Attestation_v1_r12_pub10082021.pdf#page=58>
61 pub fn new(issuer: Name, subject: Name, alt_names: Option<GeneralNames>) -> Result<Self> {
62 // If alt_name is present it is required to include `HardwareModuleName`
63 // HardwareModuleName is der-encoded in an OtherName field of GeneralNames.
64 if let Some(ref alt_names) = alt_names {
65 // TODO: do we need to validate the SAN more than that? check for duplicates?
66 let mut found = false;
67 for gn in alt_names {
68 match gn {
69 GeneralName::OtherName(on)
70 if HardwareModuleName::from_other_name(on)?.is_some() =>
71 {
72 found = true;
73 break;
74 }
75 _ => {}
76 }
77 }
78
79 if !found {
80 return Err(der::Error::from(ErrorKind::Failed).into());
81 }
82 }
83
84 Ok(Self {
85 issuer,
86 subject,
87 subject_alt_name: alt_names,
88 })
89 }
90
91 /// Create a new IDevID for a TPM-based key.
92 pub fn idevid_tpm(
93 issuer: Name,
94 subject: Name,
95 hw_type: TpmVersion,
96 serial_number: OctetString,
97 ) -> Result<Self> {
98 let hardware_module_name = HardwareModuleName {
99 hw_type: hw_type.to_oid(),
100 hw_serial_num: serial_number,
101 };
102
103 let alt_names = vec![GeneralName::OtherName(OtherName::try_from(
104 &hardware_module_name,
105 )?)];
106
107 Ok(Self {
108 issuer,
109 subject,
110 subject_alt_name: Some(alt_names),
111 })
112 }
113}
114
115impl BuilderProfile for DevId {
116 fn get_issuer(&self, _subject: &Name) -> Name {
117 self.issuer.clone()
118 }
119
120 fn get_subject(&self) -> Name {
121 self.subject.clone()
122 }
123
124 fn build_extensions(
125 &self,
126 _spk: SubjectPublicKeyInfoRef<'_>,
127 issuer_spk: SubjectPublicKeyInfoRef<'_>,
128 tbs: &TbsCertificate,
129 ) -> Result<vec::Vec<Extension>> {
130 let mut extensions: vec::Vec<Extension> = vec::Vec::new();
131
132 // # Table 8-2 - DevID certificate and intermediate certificate extensions
133
134 // ## authorityKeyIdentifier MUST
135 // Section 8.10.1
136 extensions.push(
137 AuthorityKeyIdentifier::try_from(issuer_spk.clone())?
138 .to_extension(&tbs.subject, &extensions)?,
139 );
140
141 // ## subjectKeyIdentifier NOT RECOMMENDED
142
143 // ## keyUsage SHOULD
144 // Section 8.10.3
145 //
146 // NOTE(baloo):
147 // IEEE spec allows for keyEncipherment but that would be used for TLS1.2 RSA and RSA_PSK
148 // (IE: non-DH) session scheme.
149 // In the mean time, when used with TPMs, the [TCG] will only allow for `digitalSignature`:
150 // Use of digitalSignature (only) is RECOMMENDED. Refer to section 3.8.
151 //
152 // [TCG]: https://trustedcomputinggroup.org/wp-content/uploads/TPM-2p0-Keys-for-Device-Identity-and-Attestation_v1_r12_pub10082021.pdf#page=57
153 let key_usage = KeyUsages::DigitalSignature.into();
154 extensions.push(KeyUsage(key_usage).to_extension(&tbs.subject, &extensions)?);
155
156 // ## subjectAltName SHOULD
157 // 8.10.4
158 if let Some(san) = &self.subject_alt_name {
159 extensions.push(SubjectAltName(san.clone()).to_extension(&tbs.subject, &extensions)?);
160 }
161
162 Ok(extensions)
163 }
164}
165
166/// Version of the TPM used for DevID
167#[derive(Debug, Clone, PartialEq)]
168pub enum TpmVersion {
169 /// TPM version 1.2
170 Tpm12,
171 /// TPM version 2.0
172 Tpm20,
173 /// Other TPM version
174 #[cfg(feature = "hazmat")]
175 Other(ObjectIdentifier),
176}
177
178impl TpmVersion {
179 fn to_oid(&self) -> ObjectIdentifier {
180 match self {
181 Self::Tpm12 => tcgtpm::TCG_SV_TPM_12,
182 Self::Tpm20 => tcgtpm::TCG_SV_TPM_20,
183 #[cfg(feature = "hazmat")]
184 Self::Other(o) => *o,
185 }
186 }
187}
188
189// Notes:
190// Example of a certificate can be found in A.2
191// https://trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf#page=37
192//
193// OID 2.23.133.1.0 for TPM version 1.2
194// OID 2.23.133.1.2 for TPM version 2.0
195//
196//
197// https://trustedcomputinggroup.org/wp-content/uploads/TPM-2p0-Keys-for-Device-Identity-and-Attestation_v1_r12_pub10082021.pdf#page=60
198// An IDevID/IAK complying with this specification SHOULD include tcg-cap-verifiedTPMResidency to indicate
199// compliance with section 4 and also one of tcg-cap-verifiedTPMFixed (IDevID) or tcg-cap-verifiedTPMRestricted
200// (IAK).
201//
202// tcg-cap-verifiedTPMResidency 2.23.133.11.1.1
203// tcg-cap-verifiedTPMFixed 2.23.133.11.1.2
204// tcg-cap-verifiedTPMRestricted 2.23.133.11.1.3