ot_certs/asn1/
mod.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::{Context, Result};
6
7pub mod builder;
8pub mod codegen;
9pub mod der;
10pub mod dice_tcb;
11pub mod x509;
12
13/// An ASN1 tag.
14#[derive(Debug, Copy, Clone, PartialEq, Eq)]
15pub enum Tag {
16    // Universal tags.
17    Boolean,
18    BitString,
19    GeneralizedTime,
20    Integer,
21    OctetString,
22    Oid,
23    PrintableString,
24    Sequence,
25    Set,
26    Utf8String,
27    /// Context tags.
28    Context {
29        constructed: bool,
30        value: usize,
31    },
32}
33
34/// An ASN1 object identifier.
35#[derive(Debug, Clone, PartialEq, Eq, strum::Display)]
36pub enum Oid {
37    // X509 extensions.
38    AuthorityKeyIdentifier,
39    BasicConstraints,
40    DiceTcbInfo,
41    KeyUsage,
42    SubjectKeyIdentifier,
43    // Name attributes.
44    CommonName,
45    Country,
46    Organization,
47    OrganizationalUnit,
48    SerialNumber,
49    State,
50    // Signature algorithms.
51    EcdsaWithSha256,
52    // Public key type.
53    EcPublicKey,
54    // Elliptic curve names.
55    Prime256v1,
56    // Hash algorithms.
57    Sha256,
58    // Subject alternative name and its components.
59    SubjectAltName,
60    // Vendor aka manufacturer.
61    SalTpmVendor,
62    // Tpm Model (i.e. Ti50).
63    SalTpmModel,
64    // Tpm firmware version at the time of manufacturing.
65    SalTpmVersion,
66    // Custom oid.
67    Custom(String),
68}
69
70impl Oid {
71    /// Return the standard notation of the OID as string.
72    pub fn oid(&self) -> &str {
73        match self {
74            // From https://datatracker.ietf.org/doc/html/rfc5280
75            // id-ce   OBJECT IDENTIFIER ::=  { joint-iso-ccitt(2) ds(5) 29 }
76            //
77            // id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }
78            Oid::BasicConstraints => "2.5.29.19",
79            // id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
80            Oid::KeyUsage => "2.5.29.15",
81            // id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
82            Oid::AuthorityKeyIdentifier => "2.5.29.35",
83            // id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 14 }
84            Oid::SubjectKeyIdentifier => "2.5.29.14",
85
86            // https://trustedcomputinggroup.org/wp-content/uploads/TCG_DICE_Attestation_Architecture_r22_02dec2020.pdf
87            // tcg OBJECT IDENTIFIER ::= {2 23 133}
88            // tcg-dice OBJECT IDENTIFIER ::= { tcg platformClass(5) 4 }
89            // tcg-dice-TcbInfo OBJECT IDENTIFIER ::= {tcg-dice 1}
90            Oid::DiceTcbInfo => "2.23.133.5.4.1",
91
92            // From https://www.itu.int/rec/T-REC-X.501/en
93            // ID ::= OBJECT IDENTIFIER
94            // ds ID ::= {joint-iso-itu-t ds(5)}
95            // attributeType ID ::= {ds 4}
96            // id-at ID ::= attributeType
97            //
98            // From https://www.itu.int/rec/T-REC-X.520
99            // id-at-commonName OBJECT IDENTIFIER ::= {id-at 3}
100            Oid::CommonName => "2.5.4.3",
101            // id-at-serialNumber OBJECT IDENTIFIER ::= {id-at 5}
102            Oid::SerialNumber => "2.5.4.5",
103            // id-at-countryName OBJECT IDENTIFIER ::= {id-at 6}
104            Oid::Country => "2.5.4.6",
105            // id-at-stateOrProvinceName OBJECT IDENTIFIER ::= {id-at 8}
106            Oid::State => "2.5.4.8",
107            // id-at-organizationName OBJECT IDENTIFIER ::= {id-at 10}
108            Oid::Organization => "2.5.4.10",
109            // id-at-organizationalUnitName OBJECT IDENTIFIER ::= {id-at 11}
110            Oid::OrganizationalUnit => "2.5.4.11",
111
112            // From https://datatracker.ietf.org/doc/html/rfc5758#section-3.2
113            // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
114            //      ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
115            Oid::EcdsaWithSha256 => "1.2.840.10045.4.3.2",
116
117            // From https://datatracker.ietf.org/doc/html/rfc3279
118            // ansi-X9-62  OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) 10045 }
119            // id-publicKeyType OBJECT IDENTIFIER  ::= { ansi-X9-62 keyType(2) }
120            // id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 }
121            Oid::EcPublicKey => "1.2.840.10045.2.1",
122            // ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
123            // primeCurve OBJECT IDENTIFIER ::= { ellipticCurve prime(1) }
124            // prime256v1  OBJECT IDENTIFIER  ::=  { primeCurve  7 }
125            Oid::Prime256v1 => "1.2.840.10045.3.1.7",
126
127            // From https://datatracker.ietf.org/doc/html/rfc5758#section-2
128            // id-sha256  OBJECT IDENTIFIER  ::=  { joint-iso-itu-t(2) country(16) us(840)
129            //      organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 }
130            Oid::Sha256 => "2.16.840.1.101.3.4.2.1",
131
132            // From https://www.rfc-editor.org/rfc/rfc5280.html#section-4.2.1.6
133            // subject-alt-name OBJECT_IDENTIFIER ::= { joint-iso-itu-t(2) ds(5)
134            //          certificateExtension(29) subjectAltName(17)}
135            Oid::SubjectAltName => "2.5.29.17",
136
137            // The following three object IDs come from
138            // TCG EK Credential Profile
139            // For TPM Family 2.0; Level 0
140            // Version 2.5
141            // Revision 1
142            // January 26, 2022,
143            // Section 4  X.509 ASN.1 Structures and OIDs
144            // tcg OBJECT IDENTIFIER ::= {
145            // joint-iso-itu-t(2) international-organizations(23) tcg(133)
146            // tcg-attribute OBJECT IDENTIFIER ::= {tcg 2}
147            //
148            // tcg-at-tpmManufacturer OBJECT IDENTIFIER ::= {tcg-attribute 1}
149            Oid::SalTpmVendor => "2.23.133.2.1",
150
151            // tcg-at-tpmModel OBJECT IDENTIFIER ::= {tcg-attribute 2}
152            Oid::SalTpmModel => "2.23.133.2.2",
153
154            // tcg-at-tpmVersion OBJECT IDENTIFIER ::= {tcg-attribute 3}
155            Oid::SalTpmVersion => "2.23.133.2.3",
156
157            Oid::Custom(oid) => oid,
158        }
159    }
160
161    /// Return the DER encoding of the OID as a list of bytes.
162    pub fn to_der(&self) -> Result<Vec<u8>> {
163        let mut components = self
164            .oid()
165            .split('.')
166            .map(|s| {
167                s.parse::<u32>()
168                    .with_context(|| format!("invalid OID component '{s}'"))
169            })
170            .collect::<Result<Vec<_>>>()?;
171        // From X.690 spec, section 8.19:
172        // The number of subidentifiers (N) shall be one less than the number of object identifier components
173        // in the object identifier value being encoded. The numerical value of the first subidentifier is derived
174        // from the values of the first two object identifier components in the object identifier value being encoded,
175        // using the formula: (X*40) + Y where X is the value of the first object identifier component and Y is the value
176        // of the second object identifier component.
177        components.reverse();
178        let first = components
179            .pop()
180            .context("cannot call push_oid with an empty OID")?;
181        let second = components
182            .pop()
183            .context("cannot call push_oid with a single-component OID")?;
184        components.push(40 * first + second);
185        components.reverse();
186        let mut bytes = Vec::<u8>::new();
187        for comp in components {
188            // The contents octets shall be an (ordered) list of encodings of subidentifiers (see 8.19.3 and 8.19.4) concatenated
189            // together. Each subidentifier is represented as a series of (one or more) octets. Bit 8 of each octet indicates whether it is the last in the
190            // series: bit 8 of the last octet is zero; bit 8 of each preceding octet is one. Bits 7 to 1 of the octets in the series collectively
191            // encode the subidentifier. Conceptually, these groups of bits are concatenated to form an unsigned binary number whose most
192            // significant bit is bit 7 of the first octet and whose least significant bit is bit 1 of the last octet. The subidentifier shall be
193            // encoded in the fewest possible octets, that is, the leading octet of the subidentifier shall not have the value 8016
194
195            // Compute the length that we need: each byte stores 7 bits so this is the
196            // the log in base 128 of the number.
197            let mut copy_comp = comp;
198            let mut length = 0;
199            while copy_comp > 0 {
200                length += 1;
201                copy_comp >>= 7;
202            }
203            if length == 0 {
204                length = 1;
205            }
206            // Create the bytes
207            for i in (0..length).rev() {
208                // Extract 7-bit chunk of the number.
209                let mut byte = ((comp >> (7 * i)) & 0x7f) as u8;
210                // Add continuation marker.
211                if i != 0 {
212                    byte |= 0x80;
213                }
214                bytes.push(byte);
215            }
216        }
217        Ok(bytes)
218    }
219}