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}