Skip to content

Commit 6f86303

Browse files
jwnrtpamaury
authored andcommitted
[ot_certs] Add test for parsing a Hjson cert template
Signed-off-by: James Wainwright <[email protected]> Signed-off-by: Amaury Pouly <[email protected]>
1 parent 798be91 commit 6f86303

File tree

3 files changed

+212
-1
lines changed

3 files changed

+212
-1
lines changed

quality/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ RUST_TARGETS = [
175175
"//sw/host/hsmtool:hsmlib",
176176
"//sw/host/hsmtool:hsmlib_test",
177177
"//sw/host/ot_certs:ot_certs",
178+
"//sw/host/ot_certs:ot_certs_test",
178179
"//sw/host/opentitanlib:opentitanlib",
179180
"//sw/host/opentitanlib:opentitanlib_test",
180181
"//sw/host/opentitansession:opentitansession",

sw/host/ot_certs/BUILD

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
33
# SPDX-License-Identifier: Apache-2.0
44

5-
load("@rules_rust//rust:defs.bzl", "rust_doc", "rust_library")
5+
load("@rules_rust//rust:defs.bzl", "rust_doc", "rust_library", "rust_test")
66

77
package(default_visibility = ["//visibility:public"])
88

@@ -25,6 +25,14 @@ rust_library(
2525
],
2626
)
2727

28+
rust_test(
29+
name = "ot_certs_test",
30+
crate = ":ot_certs",
31+
proc_macro_deps = [
32+
"@crate_index//:indoc",
33+
],
34+
)
35+
2836
rust_doc(
2937
name = "ot_certs_doc",
3038
crate = ":ot_certs",

sw/host/ot_certs/src/template/mod.rs

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,205 @@ impl Template {
333333
Ok(deser_hjson::from_str(content)?)
334334
}
335335
}
336+
337+
#[cfg(test)]
338+
mod tests {
339+
use super::*;
340+
use indoc::indoc;
341+
342+
/// Test parsing a typical cdi_owner template.
343+
#[test]
344+
fn cdi_owner() {
345+
// Input string for a Hjson template.
346+
let input = indoc! {r#"
347+
{
348+
name: "cdi_owner",
349+
350+
variables: {
351+
owner_pub_key_ec_x: {
352+
type: "integer",
353+
size: 32,
354+
},
355+
owner_pub_key_ec_y: {
356+
type: "integer",
357+
size: 32,
358+
},
359+
owner_pub_key_id: {
360+
type: "byte-array",
361+
size: 20,
362+
},
363+
signing_pub_key_id: {
364+
type: "byte-array",
365+
size: 20,
366+
},
367+
rom_ext_hash: {
368+
type: "byte-array",
369+
size: 20,
370+
},
371+
ownership_manifest_hash: {
372+
type: "byte-array",
373+
size: 20,
374+
},
375+
rom_ext_security_version: {
376+
type: "integer",
377+
size: 4,
378+
}
379+
layer: {
380+
type: "integer",
381+
size: 4,
382+
}
383+
cert_signature_r: {
384+
type: "integer",
385+
size: 32,
386+
},
387+
cert_signature_s: {
388+
type: "integer",
389+
size: 32,
390+
},
391+
},
392+
393+
certificate: {
394+
serial_number: { var: "owner_pub_key_id", convert: "little-endian" },
395+
issuer: {
396+
serial_number: { var: "signing_pub_key_id", convert: "lowercase-hex" },
397+
},
398+
subject: {
399+
serial_number: { var: "owner_pub_key_id", convert: "lowercase-hex" },
400+
},
401+
subject_public_key_info: {
402+
algorithm: "ec-public-key",
403+
curve: "prime256v1",
404+
public_key: {
405+
x: { var: "owner_pub_key_ec_x" },
406+
y: { var: "owner_pub_key_ec_y" },
407+
},
408+
},
409+
authority_key_identifier: { var: "signing_pub_key_id" },
410+
subject_key_identifier: { var: "owner_pub_key_id" },
411+
vendor: "OpenTitan",
412+
model: "ROM_EXT",
413+
svn: { var: "rom_ext_security_version" },
414+
layer: { var: "layer" },
415+
version: "ES",
416+
fw_ids: [
417+
{ hash_algorithm: "sha256", digest: { var: "rom_ext_hash" } },
418+
{ hash_algorithm: "sha256", digest: { var: "ownership_manifest_hash" } },
419+
],
420+
flags: {
421+
not_configured: true,
422+
not_secure: false,
423+
recovery: true,
424+
debug: false,
425+
}
426+
signature: {
427+
algorithm: "ecdsa-with-sha256",
428+
// The value field is optional: if not present, the signature will be cleared.
429+
// Otherwise, we can reference the various fields of the signature.
430+
value: {
431+
r: { var: "cert_signature_r" },
432+
s: { var: "cert_signature_s" }
433+
}
434+
}
435+
}
436+
}
437+
"#};
438+
439+
let variables = HashMap::from([
440+
(
441+
"owner_pub_key_ec_x".to_string(),
442+
VariableType::Integer { size: 32 },
443+
),
444+
(
445+
"owner_pub_key_ec_y".to_string(),
446+
VariableType::Integer { size: 32 },
447+
),
448+
(
449+
"owner_pub_key_id".to_string(),
450+
VariableType::ByteArray { size: 20 },
451+
),
452+
(
453+
"signing_pub_key_id".to_string(),
454+
VariableType::ByteArray { size: 20 },
455+
),
456+
(
457+
"rom_ext_hash".to_string(),
458+
VariableType::ByteArray { size: 20 },
459+
),
460+
(
461+
"ownership_manifest_hash".to_string(),
462+
VariableType::ByteArray { size: 20 },
463+
),
464+
(
465+
"rom_ext_security_version".to_string(),
466+
VariableType::Integer { size: 4 },
467+
),
468+
("layer".to_string(), VariableType::Integer { size: 4 }),
469+
(
470+
"cert_signature_r".to_string(),
471+
VariableType::Integer { size: 32 },
472+
),
473+
(
474+
"cert_signature_s".to_string(),
475+
VariableType::Integer { size: 32 },
476+
),
477+
]);
478+
479+
// Certificate template values.
480+
let certificate = Certificate {
481+
serial_number: Value::convert("owner_pub_key_id", Conversion::LittleEndian),
482+
issuer: HashMap::from([(
483+
AttributeType::SerialNumber,
484+
Value::convert("signing_pub_key_id", Conversion::LowercaseHex),
485+
)]),
486+
subject: HashMap::from([(
487+
AttributeType::SerialNumber,
488+
Value::convert("owner_pub_key_id", Conversion::LowercaseHex),
489+
)]),
490+
subject_public_key_info: SubjectPublicKeyInfo::EcPublicKey(EcPublicKeyInfo {
491+
curve: EcCurve::Prime256v1,
492+
public_key: EcPublicKey {
493+
x: Value::variable("owner_pub_key_ec_x"),
494+
y: Value::variable("owner_pub_key_ec_y"),
495+
},
496+
}),
497+
authority_key_identifier: Value::variable("signing_pub_key_id"),
498+
subject_key_identifier: Value::variable("owner_pub_key_id"),
499+
vendor: Some(Value::literal("OpenTitan")),
500+
model: Some(Value::literal("ROM_EXT")),
501+
svn: Some(Value::variable("rom_ext_security_version")),
502+
layer: Some(Value::variable("layer")),
503+
version: Some(Value::literal("ES")),
504+
fw_ids: Some(Vec::from([
505+
FirmwareId {
506+
hash_algorithm: HashAlgorithm::Sha256,
507+
digest: Value::variable("rom_ext_hash"),
508+
},
509+
FirmwareId {
510+
hash_algorithm: HashAlgorithm::Sha256,
511+
digest: Value::variable("ownership_manifest_hash"),
512+
},
513+
])),
514+
flags: Some(Flags {
515+
not_configured: true,
516+
not_secure: false,
517+
recovery: true,
518+
debug: false,
519+
}),
520+
signature: Signature::EcdsaWithSha256 {
521+
value: Some(EcdsaSignature {
522+
r: Value::variable("cert_signature_r"),
523+
s: Value::variable("cert_signature_s"),
524+
}),
525+
},
526+
};
527+
528+
// Compare expected and actual parsed structs.
529+
let expected = Template {
530+
name: "cdi_owner".to_string(),
531+
variables,
532+
certificate,
533+
};
534+
let actual = Template::from_hjson_str(input).expect("failed to parse template");
535+
assert_eq!(expected, actual);
536+
}
537+
}

0 commit comments

Comments
 (0)