opentitanlib/ownership/
application_key.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;
6use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
7use serde::{Deserialize, Serialize};
8use serde_annotate::Annotate;
9use std::convert::TryFrom;
10use std::io::{Read, Write};
11
12use super::GlobalFlags;
13use super::misc::{KeyMaterial, OwnershipKeyAlg, TlvHeader, TlvTag};
14use crate::with_unknown;
15
16with_unknown! {
17    pub enum ApplicationKeyDomain: u32 [default = Self::Unknown] {
18        Unknown = 0,
19        Test = u32::from_le_bytes(*b"test"),
20        Dev = u32::from_le_bytes(*b"dev_"),
21        Prod = u32::from_le_bytes(*b"prod"),
22    }
23}
24
25/// The OwnerApplicationKey is used to verify the owner's firmware payload.
26#[derive(Debug, Serialize, Deserialize, Annotate)]
27pub struct OwnerApplicationKey {
28    /// Header identifying this struct.
29    #[serde(
30        skip_serializing_if = "GlobalFlags::not_debug",
31        default = "OwnerApplicationKey::default_header"
32    )]
33    pub header: TlvHeader,
34    /// The key algorithm for this key (ECDSA, SPX+, etc).
35    pub key_alg: OwnershipKeyAlg,
36    /// The application key domain (Test, Dev, Prod).
37    pub key_domain: ApplicationKeyDomain,
38    /// A key diversification constant.  The key domain and the diversifier value are concatenated
39    /// and programmed into the key manager's binding registers.
40    #[serde(default)]
41    #[annotate(format=hex)]
42    pub key_diversifier: [u32; 7],
43    /// A usage constraint value.  This value must match the usage constraint in the manifest to
44    /// allow this key to be used.
45    #[serde(default)]
46    #[annotate(format=hex)]
47    pub usage_constraint: u32,
48    /// The key material.
49    pub key: KeyMaterial,
50}
51
52impl Default for OwnerApplicationKey {
53    fn default() -> Self {
54        Self {
55            header: Self::default_header(),
56            key_alg: OwnershipKeyAlg::default(),
57            key_domain: ApplicationKeyDomain::default(),
58            key_diversifier: [0u32; 7],
59            usage_constraint: 0u32,
60            key: KeyMaterial::default(),
61        }
62    }
63}
64
65impl OwnerApplicationKey {
66    pub fn default_header() -> TlvHeader {
67        TlvHeader::new(TlvTag::ApplicationKey, 0, "0.0")
68    }
69
70    pub fn read(src: &mut impl Read, header: TlvHeader) -> Result<Self> {
71        let key_alg = OwnershipKeyAlg(src.read_u32::<LittleEndian>()?);
72        let key_domain = ApplicationKeyDomain(src.read_u32::<LittleEndian>()?);
73        let mut key_diversifier = [0u32; 7];
74        src.read_u32_into::<LittleEndian>(&mut key_diversifier)?;
75        let usage_constraint = src.read_u32::<LittleEndian>()?;
76        let key = KeyMaterial::read_length(src, key_alg, 0)?;
77        Ok(Self {
78            header,
79            key_alg,
80            key_domain,
81            key_diversifier,
82            usage_constraint,
83            key,
84        })
85    }
86
87    pub fn write(&self, dest: &mut impl Write) -> Result<()> {
88        let header = TlvHeader::new(TlvTag::ApplicationKey, 48 + self.key.len(), "0.0");
89        header.write(dest)?;
90        dest.write_u32::<LittleEndian>(u32::from(self.key_alg))?;
91        dest.write_u32::<LittleEndian>(u32::from(self.key_domain))?;
92        for kd in &self.key_diversifier {
93            dest.write_u32::<LittleEndian>(*kd)?;
94        }
95        dest.write_u32::<LittleEndian>(self.usage_constraint)?;
96        self.key.write_length(dest, 0)?;
97        Ok(())
98    }
99}
100
101#[cfg(test)]
102mod test {
103    use super::*;
104    use crate::crypto::ecdsa::EcdsaRawPublicKey;
105    use crate::util::hexdump::{hexdump_parse, hexdump_string};
106
107    const OWNER_APPLICATION_KEY_BIN: &str = "\
10800000000: 41 50 50 4b 70 00 00 00 50 32 35 36 70 72 6f 64  APPKp...P256prod\n\
10900000010: 00 00 00 00 99 00 00 00 66 00 00 00 aa 00 00 00  ........f.......\n\
11000000020: 55 00 00 00 11 00 00 00 ee 00 00 00 77 00 00 00  U...........w...\n\
11100000030: 00 00 00 00 10 00 00 00 20 00 00 00 30 00 00 00  ........ ...0...\n\
11200000040: 40 00 00 00 50 00 00 00 60 00 00 00 70 00 00 00  @...P...`...p...\n\
11300000050: 80 00 00 00 90 00 00 00 a0 00 00 00 b0 00 00 00  ................\n\
11400000060: c0 00 00 00 d0 00 00 00 e0 00 00 00 f0 00 00 00  ................\n\
115";
116    const OWNER_APPLICATION_KEY_JSON: &str = r#"{
117  key_alg: "EcdsaP256",
118  key_domain: "Prod",
119  key_diversifier: [
120    0x0,
121    0x99,
122    0x66,
123    0xAA,
124    0x55,
125    0x11,
126    0xEE
127  ],
128  usage_constraint: 0x77,
129  key: {
130    Ecdsa: {
131      x: "0000000010000000200000003000000040000000500000006000000070000000",
132      y: "8000000090000000a0000000b0000000c0000000d0000000e0000000f0000000"
133    }
134  }
135}"#;
136
137    #[test]
138    fn test_owner_application_key_write() -> Result<()> {
139        let oak = OwnerApplicationKey {
140            header: TlvHeader::default(),
141            key_alg: OwnershipKeyAlg::EcdsaP256,
142            key_domain: ApplicationKeyDomain::Prod,
143            key_diversifier: [0x00, 0x99, 0x66, 0xAA, 0x55, 0x11, 0xEE],
144            usage_constraint: 0x77,
145            key: KeyMaterial::Ecdsa(EcdsaRawPublicKey {
146                x: hex::decode("0000000010000000200000003000000040000000500000006000000070000000")?,
147                y: hex::decode("8000000090000000a0000000b0000000c0000000d0000000e0000000f0000000")?,
148            }),
149        };
150        let mut bin = Vec::new();
151        oak.write(&mut bin)?;
152        eprintln!("{}", hexdump_string(&bin)?);
153        assert_eq!(hexdump_string(&bin)?, OWNER_APPLICATION_KEY_BIN);
154        Ok(())
155    }
156
157    #[test]
158    fn test_owner_application_key_read() -> Result<()> {
159        let buf = hexdump_parse(OWNER_APPLICATION_KEY_BIN)?;
160        let mut cur = std::io::Cursor::new(&buf);
161        let header = TlvHeader::read(&mut cur)?;
162        let oak = OwnerApplicationKey::read(&mut cur, header)?;
163        let doc = serde_annotate::serialize(&oak)?.to_json5().to_string();
164        eprintln!("{}", doc);
165        assert_eq!(doc, OWNER_APPLICATION_KEY_JSON);
166        Ok(())
167    }
168}