1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;

use crate::asn1::builder::Builder;
use crate::asn1::x509::X509;
use crate::asn1::{Oid, Tag};
use crate::template::DiceTcbInfoExtension;

impl DiceTcbInfoExtension {
    // From the DICE specification:
    // https://trustedcomputinggroup.org/wp-content/uploads/DICE-Attestation-Architecture-r23-final.pdf
    //
    // tcg OBJECT IDENTIFIER ::= {2 23 133}
    // tcg-dice OBJECT IDENTIFIER ::= { tcg platformClass(5) 4 }
    // tcg-dice-TcbInfo OBJECT IDENTIFIER ::= {tcg-dice 1}
    // DiceTcbInfo ::== SEQUENCE {
    //     vendor [0] IMPLICIT UTF8String OPTIONAL,
    //     model [1] IMPLICIT UTF8String OPTIONAL,
    //     version [2] IMPLICIT UTF8String OPTIONAL,
    //     svn [3] IMPLICIT INTEGER OPTIONAL,
    //     layer [4] IMPLICIT INTEGER OPTIONAL,
    //     index [5] IMPLICIT INTEGER OPTIONAL,
    //     fwids [6] IMPLICIT FWIDLIST OPTIONAL,
    //     flags [7] IMPLICIT OperationalFlags OPTIONAL,
    //     vendorInfo [8] IMPLICIT OCTET STRING OPTIONAL,
    //     type [9] IMPLICIT OCTET STRING OPTIONAL
    // }
    // FWIDLIST ::== SEQUENCE SIZE (1..MAX) OF FWID
    //     FWID ::== SEQUENCE {
    //     hashAlg OBJECT IDENTIFIER,
    //     digest OCTET STRING
    // }
    // OperationalFlags ::= BIT STRING {
    //     notConfigured (0),
    //     notSecure (1),
    //     recovery (2),
    //     debug (3)
    // }

    // Push a raw DICE TCB Info extension data, without the X509 extension header.
    pub fn push_extension_raw<B: Builder>(&self, builder: &mut B) -> Result<()> {
        builder.push_seq(Some("dice_tcb_info".into()), |builder| {
            if let Some(vendor) = &self.vendor {
                builder.push_string(
                    Some("dice_vendor".into()),
                    &Tag::Context {
                        constructed: false,
                        value: 0,
                    },
                    vendor,
                )?;
            }
            if let Some(model) = &self.model {
                builder.push_string(
                    Some("dice_model".into()),
                    &Tag::Context {
                        constructed: false,
                        value: 1,
                    },
                    model,
                )?;
            }
            if let Some(version) = &self.version {
                builder.push_string(
                    Some("dice_version".into()),
                    &Tag::Context {
                        constructed: false,
                        value: 2,
                    },
                    version,
                )?;
            }
            if let Some(svn) = &self.svn {
                builder.push_integer(
                    Some("dice_svn".into()),
                    &Tag::Context {
                        constructed: false,
                        value: 3,
                    },
                    svn,
                )?;
            }
            if let Some(layer) = &self.layer {
                builder.push_integer(
                    Some("dice_layer".into()),
                    &Tag::Context {
                        constructed: false,
                        value: 4,
                    },
                    layer,
                )?;
            }
            if let Some(fwids) = &self.fw_ids {
                builder.push_tag(
                    Some("dice_fwids".into()),
                    &Tag::Context {
                        constructed: true,
                        value: 6,
                    },
                    |builder| {
                        for (idx, fwid) in fwids.iter().enumerate() {
                            builder.push_seq(Some("fwid".into()), |builder| {
                                builder.push_oid(&fwid.hash_algorithm.oid())?;
                                builder.push_octet_string(
                                    Some(format!("dice_fwids_{}", idx)),
                                    |builder| {
                                        builder.push_byte_array(
                                            Some(format!("dice_fwids_{}", idx)),
                                            &fwid.digest,
                                        )
                                    },
                                )
                            })?;
                        }
                        Ok(())
                    },
                )?;
            }
            if let Some(flags) = &self.flags {
                builder.push_bitstring(
                    Some("dice_flags".into()),
                    &Tag::Context {
                        constructed: false,
                        value: 7,
                    },
                    &[
                        flags.not_configured.clone(),
                        flags.not_secure.clone(),
                        flags.recovery.clone(),
                        flags.debug.clone(),
                    ],
                )?;
            }
            Ok(())
        })
    }

    // Push a DICE TCB Info X509 extension.
    pub fn push_extension<B: Builder>(&self, builder: &mut B) -> Result<()> {
        // Per the DICE specification, the DiceTcbInfo extension SHOULD be marked critical.
        X509::push_extension(builder, &Oid::DiceTcbInfo, true, |builder| {
            self.push_extension_raw(builder)
        })
    }
}