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