ot_certs/asn1/
dice_tcb.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::Result;
6
7use crate::asn1::builder::Builder;
8use crate::asn1::x509::X509;
9use crate::asn1::{Oid, Tag};
10use crate::template::DiceTcbInfoExtension;
11
12impl DiceTcbInfoExtension {
13    // From the DICE specification:
14    // https://trustedcomputinggroup.org/wp-content/uploads/DICE-Attestation-Architecture-r23-final.pdf
15    //
16    // tcg OBJECT IDENTIFIER ::= {2 23 133}
17    // tcg-dice OBJECT IDENTIFIER ::= { tcg platformClass(5) 4 }
18    // tcg-dice-TcbInfo OBJECT IDENTIFIER ::= {tcg-dice 1}
19    // DiceTcbInfo ::== SEQUENCE {
20    //     vendor [0] IMPLICIT UTF8String OPTIONAL,
21    //     model [1] IMPLICIT UTF8String OPTIONAL,
22    //     version [2] IMPLICIT UTF8String OPTIONAL,
23    //     svn [3] IMPLICIT INTEGER OPTIONAL,
24    //     layer [4] IMPLICIT INTEGER OPTIONAL,
25    //     index [5] IMPLICIT INTEGER OPTIONAL,
26    //     fwids [6] IMPLICIT FWIDLIST OPTIONAL,
27    //     flags [7] IMPLICIT OperationalFlags OPTIONAL,
28    //     vendorInfo [8] IMPLICIT OCTET STRING OPTIONAL,
29    //     type [9] IMPLICIT OCTET STRING OPTIONAL
30    // }
31    // FWIDLIST ::== SEQUENCE SIZE (1..MAX) OF FWID
32    //     FWID ::== SEQUENCE {
33    //     hashAlg OBJECT IDENTIFIER,
34    //     digest OCTET STRING
35    // }
36    // OperationalFlags ::= BIT STRING {
37    //     notConfigured (0),
38    //     notSecure (1),
39    //     recovery (2),
40    //     debug (3)
41    // }
42
43    // Push a raw DICE TCB Info extension data, without the X509 extension header.
44    pub fn push_extension_raw<B: Builder>(&self, builder: &mut B) -> Result<()> {
45        builder.push_seq(Some("dice_tcb_info".into()), |builder| {
46            if let Some(vendor) = &self.vendor {
47                builder.push_string(
48                    Some("dice_vendor".into()),
49                    &Tag::Context {
50                        constructed: false,
51                        value: 0,
52                    },
53                    vendor,
54                )?;
55            }
56            if let Some(model) = &self.model {
57                builder.push_string(
58                    Some("dice_model".into()),
59                    &Tag::Context {
60                        constructed: false,
61                        value: 1,
62                    },
63                    model,
64                )?;
65            }
66            if let Some(version) = &self.version {
67                builder.push_string(
68                    Some("dice_version".into()),
69                    &Tag::Context {
70                        constructed: false,
71                        value: 2,
72                    },
73                    version,
74                )?;
75            }
76            if let Some(svn) = &self.svn {
77                builder.push_integer(
78                    Some("dice_svn".into()),
79                    &Tag::Context {
80                        constructed: false,
81                        value: 3,
82                    },
83                    svn,
84                )?;
85            }
86            if let Some(layer) = &self.layer {
87                builder.push_integer(
88                    Some("dice_layer".into()),
89                    &Tag::Context {
90                        constructed: false,
91                        value: 4,
92                    },
93                    layer,
94                )?;
95            }
96            if let Some(fwids) = &self.fw_ids {
97                builder.push_tag(
98                    Some("dice_fwids".into()),
99                    &Tag::Context {
100                        constructed: true,
101                        value: 6,
102                    },
103                    |builder| {
104                        for (idx, fwid) in fwids.iter().enumerate() {
105                            builder.push_seq(Some("fwid".into()), |builder| {
106                                builder.push_oid(&fwid.hash_algorithm.oid())?;
107                                builder.push_octet_string(
108                                    Some(format!("dice_fwids_{}", idx)),
109                                    |builder| {
110                                        builder.push_byte_array(
111                                            Some(format!("dice_fwids_{}", idx)),
112                                            &fwid.digest,
113                                        )
114                                    },
115                                )
116                            })?;
117                        }
118                        Ok(())
119                    },
120                )?;
121            }
122            if let Some(flags) = &self.flags {
123                builder.push_bitstring(
124                    Some("dice_flags".into()),
125                    &Tag::Context {
126                        constructed: false,
127                        value: 7,
128                    },
129                    &[
130                        flags.not_configured.clone(),
131                        flags.not_secure.clone(),
132                        flags.recovery.clone(),
133                        flags.debug.clone(),
134                    ],
135                )?;
136            }
137            Ok(())
138        })
139    }
140
141    // Push a DICE TCB Info X509 extension.
142    pub fn push_extension<B: Builder>(&self, builder: &mut B) -> Result<()> {
143        // Per the DICE specification, the DiceTcbInfo extension SHOULD be marked critical.
144        X509::push_extension(builder, &Oid::DiceTcbInfo, true, |builder| {
145            self.push_extension_raw(builder)
146        })
147    }
148}