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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
use super::key::KeyType;
use super::usage::Usage;
use openssl::hash::MessageDigest;
use openssl::pkey::{PKey, Private};
use std::collections::HashSet;
macro_rules! vec_str_to_hs {
($vec:expr) => {
$vec.iter()
.map(|s| s.to_string())
.collect::<HashSet<String>>()
};
}
/// Defines which hash algorithm to be used in certificate signing
#[derive(Debug, Clone)]
pub enum HashAlg {
/// SHA-1 (Secure Hash Algorithm 1), now considered weak and generally discouraged for new certificates.
SHA1,
/// SHA-256 (part of SHA-2 family)
SHA256,
/// SHA-384 (SHA-2 family), offers stronger security and is often used with larger key sizes.
SHA384,
/// SHA-512 (SHA-2 family), provides the highest bit-length hash in the SHA-2 family.
SHA512,
}
/// Defines a common interface for setting X509 certificate or CSR builder fields.
pub trait BuilderCommon {
fn set_common_name(&mut self, name: &str);
fn set_signer(&mut self, signer: &str);
fn set_country_name(&mut self, name: &str);
fn set_state_province(&mut self, name: &str);
fn set_organization(&mut self, name: &str);
fn set_organization_unit(&mut self, name: &str);
fn set_alternative_names(&mut self, alternative_names: Vec<&str>);
fn set_locality_time(&mut self, locality_time: &str);
fn set_key_type(&mut self, key_type: KeyType);
fn set_signature_alg(&mut self, signature_alg: HashAlg);
fn set_key_usage(&mut self, key_usage: HashSet<Usage>);
fn set_private_key(&mut self, pkey: PKey<Private>);
}
/// Stores common configurable fields used during X509 certificate or CSR generation.
#[derive(Debug)]
pub struct BuilderFields {
pub(crate) common_name: String,
pub(crate) signer: Option<String>, //place holder for maybe future use??
pub(crate) alternative_names: HashSet<String>,
pub(crate) organization_unit: String,
pub(crate) country_name: String,
pub(crate) state_province: String,
pub(crate) organization: String,
pub(crate) locality_time: String,
pub(crate) key_type: Option<KeyType>,
pub(crate) existing_key: Option<PKey<Private>>,
pub(crate) signature_alg: Option<HashAlg>,
pub(crate) usage: Option<HashSet<Usage>>,
}
impl BuilderCommon for BuilderFields {
// Sets the common name, CN. Whether it also appears in the SAN is decided
// when the certificate is built, since it depends on the CA flag.
fn set_common_name(&mut self, common_name: &str) {
self.common_name = common_name.into();
}
// The alternative names (SAN) the caller asked for. The CN is not merged in
// here — see the SAN assembly in prepare_x509_builder.
fn set_alternative_names(&mut self, alternative_names: Vec<&str>) {
self.alternative_names
.extend(vec_str_to_hs!(alternative_names));
}
// maybe
fn set_signer(&mut self, signer: &str) {
self.signer = Some(signer.into());
}
// Country, a valid two char value
fn set_country_name(&mut self, country_name: &str) {
self.country_name = country_name.into();
}
// State, province an utf-8 value
fn set_state_province(&mut self, state_province: &str) {
self.state_province = state_province.into();
}
// Org. an utf-8 value
fn set_organization(&mut self, organization: &str) {
self.organization = organization.into();
}
// Org. unit an utf-8 value
fn set_organization_unit(&mut self, organization_unit: &str) {
self.organization_unit = organization_unit.into();
}
// Locality, represents the city, town, or locality of the certificate subject
fn set_locality_time(&mut self, locality_time: &str) {
self.locality_time = locality_time.into();
}
// Selects what type of key to use RSA or elliptic
fn set_key_type(&mut self, key_type: KeyType) {
self.key_type = Some(key_type);
}
// Selects what alg to use for signature
fn set_signature_alg(&mut self, signature_alg: HashAlg) {
self.signature_alg = Some(signature_alg);
}
// Sets a private key to be used
fn set_private_key(&mut self, pkey: PKey<Private>) {
self.existing_key = Some(pkey);
}
// Set what the certificate are allowed to do, KeyUsage and ExtendeKeyUsage
fn set_key_usage(&mut self, key_usage: HashSet<Usage>) {
match &mut self.usage {
Some(existing_usage) => {
existing_usage.extend(key_usage);
}
None => {
self.usage = Some(key_usage);
}
};
}
}
impl Default for BuilderFields {
/// Returns default values for all fields
fn default() -> Self {
Self {
common_name: Default::default(),
signer: Default::default(),
alternative_names: Default::default(),
country_name: Default::default(),
state_province: Default::default(),
organization: Default::default(),
organization_unit: Default::default(),
locality_time: Default::default(),
key_type: Default::default(),
signature_alg: Default::default(),
usage: Default::default(),
existing_key: Default::default(),
}
}
}
/// Provides a builder interface for configuring X509 certificate or CSR fields.
pub trait UseesBuilderFields: Sized {
/// Returns a mutable reference to the internal `BuilderFields` structure.
fn fields_mut(&mut self) -> &mut BuilderFields;
/// Sets the Common Name (CN) of the certificate subject.
///
/// For **end-entity** certificates the CN is also added to the Subject
/// Alternative Names, because RFC 6125 verifiers match the hostname against
/// the SAN and ignore the CN entirely.
///
/// **CA** certificates receive no SAN, so the CN is not copied there — a CA
/// is identified by its distinguished name and key identifier during path
/// validation.
fn common_name(mut self, common_name: &str) -> Self {
self.fields_mut().set_common_name(common_name);
self
}
/// Sets the signer name or identifier for the certificate.
fn signer(mut self, signer: &str) -> Self {
self.fields_mut().set_signer(signer);
self
}
/// Sets the list of Subject Alternative Names (SAN).
///
/// An entry that parses as an IPv4 or IPv6 address is emitted as an
/// `iPAddress` name, everything else as a `dNSName`.
///
/// For end-entity certificates the Common Name is added to this list
/// automatically. CA certificates are issued without a SAN, and an empty
/// list produces no extension at all rather than an empty one.
fn alternative_names(mut self, alternative_names: Vec<&str>) -> Self {
self.fields_mut().set_alternative_names(alternative_names);
self
}
/// Sets the country name (C), which must be a valid two-letter country code.
fn country_name(mut self, country_name: &str) -> Self {
self.fields_mut().set_country_name(country_name);
self
}
/// Sets the state or province name (ST) as a UTF-8 string.
fn state_province(mut self, state_province: &str) -> Self {
self.fields_mut().set_state_province(state_province);
self
}
/// Sets the organization name (O) as a UTF-8 string.
fn organization(mut self, organization: &str) -> Self {
self.fields_mut().set_organization(organization);
self
}
/// Sets the locality name (L), typically representing the city or town.
fn locality_time(mut self, locality_time: &str) -> Self {
self.fields_mut().set_locality_time(locality_time);
self
}
/// Sets the type of key to generate (e.g., RSA or Elliptic Curve).
fn key_type(mut self, key_type: KeyType) -> Self {
self.fields_mut().set_key_type(key_type);
self
}
/// Use a private key you already hold instead of generating a new one.
///
/// This takes precedence over [`key_type`](Self::key_type): if both are set
/// the supplied key wins and the requested key type is ignored, since the
/// algorithm is a property of the key itself.
///
/// Useful for re-issuing a certificate against an existing key (so deployed
/// configuration and any pinning keep working), and for minting many
/// certificates cheaply — key generation, not signing, is the expensive part
/// of issuance.
///
/// Reusing one key across certificates is a deliberate trade-off: a
/// compromise of that key affects every certificate issued from it. Prefer a
/// fresh key per certificate unless you have a specific reason not to.
fn private_key(mut self, pkey: PKey<Private>) -> Self {
self.fields_mut().set_private_key(pkey);
self
}
/// Sets the signature algorithm to use when signing the certificate.
fn signature_alg(mut self, signature_alg: HashAlg) -> Self {
self.fields_mut().set_signature_alg(signature_alg);
self
}
/// Sets the allowed usages for the certificate (e.g., key signing, digital signature).
///
/// This includes both `KeyUsage` and `ExtendedKeyUsage` extensions.
fn key_usage(mut self, key_usage: HashSet<Usage>) -> Self {
self.fields_mut().set_key_usage(key_usage);
self
}
}
pub(crate) fn select_hash(hash_type: &Option<HashAlg>) -> MessageDigest {
match hash_type {
Some(HashAlg::SHA1) => MessageDigest::sha1(),
Some(HashAlg::SHA384) => MessageDigest::sha384(),
Some(HashAlg::SHA512) => MessageDigest::sha512(),
_ => MessageDigest::sha256(),
}
}