x509_cert/builder/profile/
cabf.rs1use alloc::{collections::BTreeSet, vec};
6
7use crate::{
8 builder::{BuilderProfile, Error, Result},
9 certificate::TbsCertificate,
10 ext::{
11 Extension, ToExtension,
12 pkix::{
13 AuthorityKeyIdentifier, BasicConstraints, KeyUsage, KeyUsages, SubjectKeyIdentifier,
14 },
15 },
16 name::Name,
17};
18use const_oid::db::{rfc2256, rfc4519};
19use spki::SubjectPublicKeyInfoRef;
20
21pub fn check_names_encoding(name: &Name, multiple_allowed: bool) -> Result<()> {
27 let enforce_ordering = vec![
30 rfc4519::DOMAIN_COMPONENT,
31 rfc4519::COUNTRY_NAME,
32 rfc2256::STATE_OR_PROVINCE_NAME,
33 rfc4519::LOCALITY_NAME,
34 rfc4519::POSTAL_CODE,
35 rfc2256::STREET_ADDRESS,
36 rfc4519::ORGANIZATION_NAME,
37 rfc4519::SURNAME,
38 rfc4519::GIVEN_NAME,
39 rfc4519::ORGANIZATIONAL_UNIT_NAME,
40 rfc4519::COMMON_NAME,
41 ];
42 let mut ordering = enforce_ordering.iter();
43
44 let mut seen = BTreeSet::new();
45
46 for rdn in name.iter_rdn() {
47 if rdn.len() != 1 {
48 return Err(Error::NonUniqueRdn);
49 }
50
51 for atv in rdn.iter() {
52 if !multiple_allowed && !seen.insert(atv.oid) {
53 return Err(Error::NonUniqueATV);
54 }
55
56 if enforce_ordering.iter().any(|attr| attr == &atv.oid) {
58 if !ordering.any(|attr| attr == &atv.oid) {
60 return Err(Error::InvalidAttribute { oid: atv.oid });
61 }
62 }
63 }
64 }
65
66 Ok(())
67}
68
69pub fn ca_certificate_naming(subject: &Name) -> Result<()> {
73 let mut required = BTreeSet::from([
74 rfc4519::COUNTRY_NAME,
75 rfc4519::ORGANIZATION_NAME,
76 rfc4519::COMMON_NAME,
77 ]);
78 let mut allowed = BTreeSet::from([
79 rfc4519::COUNTRY_NAME,
80 rfc2256::STATE_OR_PROVINCE_NAME,
81 rfc4519::LOCALITY_NAME,
82 rfc4519::POSTAL_CODE,
83 rfc2256::STREET_ADDRESS,
84 rfc4519::ORGANIZATION_NAME,
85 rfc4519::COMMON_NAME,
86 ]);
87
88 check_names_encoding(subject, false)?;
89
90 for atv in subject.iter() {
91 if !allowed.remove(&atv.oid) {
92 return Err(Error::InvalidAttribute { oid: atv.oid });
93 }
94 required.remove(&atv.oid);
95 }
96
97 if !required.is_empty() {
98 return Err(Error::MissingAttributes);
99 }
100
101 Ok(())
102}
103
104pub struct Root {
108 pub emits_ocsp_response: bool,
111 subject: Name,
112}
113
114impl Root {
115 pub fn new(emits_ocsp_response: bool, subject: Name) -> Result<Self> {
117 ca_certificate_naming(&subject)?;
118
119 Ok(Self {
120 emits_ocsp_response,
121 subject,
122 })
123 }
124}
125
126impl BuilderProfile for Root {
127 fn get_issuer(&self, subject: &Name) -> Name {
128 subject.clone()
129 }
130
131 fn get_subject(&self) -> Name {
132 self.subject.clone()
133 }
134
135 fn build_extensions(
136 &self,
137 spk: SubjectPublicKeyInfoRef<'_>,
138 _issuer_spk: SubjectPublicKeyInfoRef<'_>,
139 tbs: &TbsCertificate,
140 ) -> Result<vec::Vec<Extension>> {
141 let mut extensions: vec::Vec<Extension> = vec::Vec::new();
142
143 let ski = SubjectKeyIdentifier::try_from(spk)?;
146
147 extensions.push(
150 AuthorityKeyIdentifier {
151 key_identifier: Some(ski.0.clone()),
153 ..Default::default()
155 }
156 .to_extension(&tbs.subject, &extensions)?,
157 );
158
159 extensions.push(
162 BasicConstraints {
163 ca: true,
164 path_len_constraint: None,
165 }
166 .to_extension(&tbs.subject, &extensions)?,
167 );
168
169 let mut key_usage = KeyUsages::KeyCertSign | KeyUsages::CRLSign;
172 if self.emits_ocsp_response {
173 key_usage |= KeyUsages::DigitalSignature;
174 }
175 extensions.push(KeyUsage(key_usage).to_extension(&tbs.subject, &extensions)?);
176
177 extensions.push(ski.to_extension(&tbs.subject, &extensions)?);
186
187 Ok(extensions)
196 }
197
198 }
211
212pub mod tls;
213
214pub mod codesigning {
215 }
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222 use core::str::FromStr;
223
224 #[test]
225 fn test_check_names() {
226 assert!(
227 check_names_encoding(&Name::from_str("C=US,ST=CA").expect("parse name"), false)
228 .is_err()
229 );
230 assert!(
231 check_names_encoding(&Name::from_str("ST=CA,C=US").expect("parse name"), false).is_ok()
232 );
233 assert!(
234 check_names_encoding(
235 &Name::from_str("serialNumber=1234,ST=CA,C=US").expect("parse name"),
236 false
237 )
238 .is_ok()
239 );
240 }
241}