Skip to content

Commit 7a95eb3

Browse files
committed
Add tool to generate DCSRs from a public key & profile name.
1 parent 1dbc437 commit 7a95eb3

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

src/bin/dcsr-gen.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
use anyhow::Context;
6+
use clap::{Parser, ValueEnum};
7+
use lpc55_areas::{DebugFieldSetting, DebugSettings};
8+
use lpc55_sign::debug_auth::DebugCredentialSigningRequest;
9+
use rsa::{pkcs8::DecodePublicKey, RsaPublicKey};
10+
use std::{
11+
fs::File,
12+
io::{self, Read, Write},
13+
path::PathBuf,
14+
};
15+
16+
#[derive(Debug, Clone, Copy, ValueEnum)]
17+
enum Profile {
18+
BootlebyImageSelection,
19+
PlatformIdentityProgramming,
20+
PostSecretScrub,
21+
PreSecretScrub,
22+
}
23+
24+
const DISABLED_SETTINGS: DebugSettings = DebugSettings {
25+
non_invasive_debug: DebugFieldSetting::AlwaysDisabled,
26+
invasive_debug: DebugFieldSetting::AlwaysDisabled,
27+
secure_non_invasive_debug: DebugFieldSetting::AlwaysDisabled,
28+
secure_invasive_debug: DebugFieldSetting::AlwaysDisabled,
29+
cpu1_dbg_enable: DebugFieldSetting::AlwaysDisabled,
30+
cpu1_non_invasive_enable: DebugFieldSetting::AlwaysDisabled,
31+
tap_enable: DebugFieldSetting::AlwaysDisabled,
32+
isp_enable: DebugFieldSetting::AlwaysDisabled,
33+
fa_me_enable: DebugFieldSetting::AlwaysDisabled,
34+
uuid_check: false,
35+
};
36+
37+
const BOOTLEBY_IMAGE_SELECTION_SETTINGS: DebugSettings = DISABLED_SETTINGS;
38+
39+
const PLATFORM_IDENTITY_PROGRAMMING_SETTINGS: DebugSettings = DISABLED_SETTINGS;
40+
41+
const POST_SECRET_SCRUB_SETTINGS: DebugSettings = DebugSettings {
42+
non_invasive_debug: DebugFieldSetting::DebugAuth,
43+
invasive_debug: DebugFieldSetting::DebugAuth,
44+
secure_non_invasive_debug: DebugFieldSetting::DebugAuth,
45+
secure_invasive_debug: DebugFieldSetting::DebugAuth,
46+
cpu1_dbg_enable: DebugFieldSetting::AlwaysDisabled,
47+
cpu1_non_invasive_enable: DebugFieldSetting::AlwaysDisabled,
48+
tap_enable: DebugFieldSetting::AlwaysDisabled,
49+
isp_enable: DebugFieldSetting::AlwaysDisabled,
50+
fa_me_enable: DebugFieldSetting::AlwaysDisabled,
51+
uuid_check: false,
52+
};
53+
54+
const PRE_SECRET_SCRUB_SETTINGS: DebugSettings = DebugSettings {
55+
non_invasive_debug: DebugFieldSetting::DebugAuth,
56+
invasive_debug: DebugFieldSetting::DebugAuth,
57+
secure_non_invasive_debug: DebugFieldSetting::DebugAuth,
58+
secure_invasive_debug: DebugFieldSetting::DebugAuth,
59+
cpu1_dbg_enable: DebugFieldSetting::DebugAuth,
60+
cpu1_non_invasive_enable: DebugFieldSetting::DebugAuth,
61+
tap_enable: DebugFieldSetting::AlwaysDisabled,
62+
isp_enable: DebugFieldSetting::DebugAuth,
63+
fa_me_enable: DebugFieldSetting::AlwaysDisabled,
64+
uuid_check: false,
65+
};
66+
67+
impl Profile {
68+
/// We do not generate UUID specific debug auth credentials. This returns
69+
/// all zeros
70+
fn uuid(&self) -> [u8; 16] {
71+
[0u8; 16]
72+
}
73+
74+
/// We do not set the vendor usage field. This returns 0.
75+
fn vendor_usage(&self) -> u32 {
76+
0
77+
}
78+
79+
/// Map `Profile` to OANA beacon values
80+
fn beacon(&self) -> u16 {
81+
match self {
82+
Profile::BootlebyImageSelection => 18578,
83+
Profile::PlatformIdentityProgramming => 53710,
84+
Profile::PostSecretScrub => 1000,
85+
Profile::PreSecretScrub => 0,
86+
}
87+
}
88+
89+
/// Map `Profile` to `DebugSettings` per RFD 333
90+
fn debug_settings(&self) -> DebugSettings {
91+
match self {
92+
Profile::BootlebyImageSelection => {
93+
BOOTLEBY_IMAGE_SELECTION_SETTINGS
94+
}
95+
Profile::PlatformIdentityProgramming => {
96+
PLATFORM_IDENTITY_PROGRAMMING_SETTINGS
97+
}
98+
Profile::PostSecretScrub => POST_SECRET_SCRUB_SETTINGS,
99+
Profile::PreSecretScrub => PRE_SECRET_SCRUB_SETTINGS,
100+
}
101+
}
102+
}
103+
104+
/// Generate a Debug Credential Signing Request
105+
#[derive(Parser, Debug)]
106+
struct Args {
107+
/// output path for generated DCSR, stdout if omitted
108+
#[clap(long)]
109+
out: Option<PathBuf>,
110+
111+
/// debug authentication credential profile
112+
#[arg(value_enum)]
113+
profile: Profile,
114+
115+
/// path to RSA public key as SPKI, stdin if omitted
116+
public_key: Option<PathBuf>,
117+
}
118+
119+
fn main() -> anyhow::Result<()> {
120+
let args = Args::parse();
121+
122+
// get a reader appropriate to the input method
123+
let reader: Box<dyn Read> = match args.public_key {
124+
Some(ref i) => Box::new(File::open(i)?),
125+
None => Box::new(io::stdin()),
126+
};
127+
128+
// read public key from file
129+
let pem = io::read_to_string(reader).with_context(|| {
130+
let src = match args.public_key {
131+
Some(ref i) => format!("{}", i.display()),
132+
None => "stdin".to_string(),
133+
};
134+
format!("reading public key from: {src}")
135+
})?;
136+
137+
// transform public key from PEM encoded SPKI to `RsaPublicKey`
138+
let debug_public_key = RsaPublicKey::from_public_key_pem(&pem)
139+
.context("parsing RSA public key from SPKI")?;
140+
141+
// create `DebugCredentialSigningRequest` from the provided public key &
142+
// debug authentication credential profile
143+
let dcsr = DebugCredentialSigningRequest {
144+
debug_public_key,
145+
uuid: args.profile.uuid(),
146+
vendor_usage: args.profile.vendor_usage(),
147+
debug_settings: args.profile.debug_settings(),
148+
beacon: args.profile.beacon(),
149+
};
150+
151+
// get a writer appropriate to the output method
152+
let mut writer: Box<dyn Write> = match args.out {
153+
Some(o) => Box::new(File::create(o)?),
154+
None => Box::new(io::stdout()),
155+
};
156+
157+
// output DCSR as pretty JSON
158+
serde_json::to_writer_pretty(&mut writer, &dcsr)
159+
.context("failed to write DCSR to writer")
160+
}

0 commit comments

Comments
 (0)