ot_certs/asn1/builder.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
5//! This module provides a trait to abstract the generation of an ASN1
6//! document. The particularity of this trait is that the base values
7//! are of type `Value<T>` which can either be literals or variables.
8
9use anyhow::{Result, ensure};
10use num_bigint_dig::BigUint;
11
12use crate::asn1::{Oid, Tag};
13use crate::template::Value;
14
15/// Helper function to add a suffix to a name hint.
16pub fn concat_suffix(name_hint: &Option<String>, suffix: &str) -> Option<String> {
17 name_hint.as_ref().map(|s| format!("{}_{}", s, suffix))
18}
19
20/// Trait for an abstract ASN1 builder.
21///
22/// This builder does not specify what the output is, but only provides
23/// basic functions to build an ASN1 document. A possible implementation
24/// would be to output bytes to produce an actual DER encoding for example.
25/// This can also be used to generate C code that calls into a C library to
26/// produce a certificate. For this reason, this builder does not provide any
27/// way to access the result, as this is implementation specific.
28pub trait Builder {
29 /// Push a byte into the ASN1 output.
30 fn push_byte(&mut self, val: u8) -> Result<()>;
31
32 /// Push a tagged boolean into the ASN1 output.
33 fn push_boolean(&mut self, tag: &Tag, val: &Value<bool>) -> Result<()>;
34
35 /// Push a tagged integer into the ASN1 output. The name hint can be used by
36 /// the implementation for documentation purpose, or completely ignored.
37 fn push_integer(
38 &mut self,
39 name_hint: Option<String>,
40 tag: &Tag,
41 val: &Value<BigUint>,
42 ) -> Result<()>;
43
44 /// Push a byte array into the ASN1 output, representing an integer. If the provided
45 /// buffer is smaller than the provided size, it will be padded with zeroes. Note that this
46 /// function does not add a tag to the ASN1 output.
47 fn push_integer_pad(
48 &mut self,
49 name_hint: Option<String>,
50 val: &Value<BigUint>,
51 size: usize,
52 ) -> Result<()>;
53
54 /// Push a byte array of fixed length into the ASN1 output. Note that this function does not add a tag to
55 /// the ASN1 output.
56 fn push_byte_array(&mut self, name_hint: Option<String>, val: &Value<Vec<u8>>) -> Result<()>;
57
58 /// Push a tagged string into the ASN1 output.
59 fn push_string(
60 &mut self,
61 name_hint: Option<String>,
62 str_type: &Tag,
63 val: &Value<String>,
64 ) -> Result<()>;
65
66 /// Push a tagged object identifier into the ASN1 output.
67 fn push_oid(&mut self, oid: &Oid) -> Result<()>;
68
69 /// Push tagged content into the ASN1 output. The closure can use any available function of the builder
70 /// and produces the content of the tagged data.
71 fn push_tag(
72 &mut self,
73 name_hint: Option<String>,
74 tag: &Tag,
75 build: impl FnOnce(&mut Self) -> Result<()>,
76 ) -> Result<()>;
77
78 /// Push a tagged octet string into the ASN1 output. The closure can use any available function of the builder
79 /// and produces the content of the octet string.
80 fn push_octet_string(
81 &mut self,
82 name_hint: Option<String>,
83 build: impl FnOnce(&mut Self) -> Result<()>,
84 ) -> Result<()> {
85 self.push_tag(name_hint, &Tag::OctetString, |builder| build(builder))
86 }
87
88 /// Push a sequence into the ASN1 output. The closure can use any available function of the builder
89 /// and produces the content of the sequence.
90 fn push_seq(
91 &mut self,
92 name_hint: Option<String>,
93 build: impl FnOnce(&mut Self) -> Result<()>,
94 ) -> Result<()> {
95 self.push_tag(name_hint, &Tag::Sequence, build)
96 }
97
98 /// Push a sequence into the ASN1 output. The closure can use any available function of the builder
99 /// and produces the content of the set.
100 fn push_set(
101 &mut self,
102 name_hint: Option<String>,
103 build: impl FnOnce(&mut Self) -> Result<()>,
104 ) -> Result<()> {
105 self.push_tag(name_hint, &Tag::Set, build)
106 }
107
108 /// Push tagged content into the ASN1 output as a bitstring. The closure can use any available function of the builder
109 /// and the resulting content will be stored as a BITSTRING using the provided tag and unused number of bits.
110 fn push_as_bit_string(
111 &mut self,
112 name_hint: Option<String>,
113 tag: &Tag,
114 unused_bits: usize,
115 build: impl FnOnce(&mut Self) -> Result<()>,
116 ) -> Result<()> {
117 self.push_tag(name_hint, tag, |builder| {
118 ensure!(
119 unused_bits <= 7,
120 "unused bits value must be in the range 0 to 7"
121 );
122 builder.push_byte(unused_bits as u8)?;
123 build(builder)
124 })
125 }
126
127 // Push a tagged constant bit string into the ASN1 output.
128 fn push_bitstring(
129 &mut self,
130 name_hint: Option<String>,
131 tag: &Tag,
132 bits: &[Value<bool>],
133 ) -> Result<()>;
134}