11//! X509 Certificate builder
22
33use alloc:: vec;
4- use core:: fmt;
4+ use core:: { fmt, marker :: PhantomData } ;
55use der:: { asn1:: BitString , referenced:: OwnedToRef , Encode } ;
66use signature:: { rand_core:: CryptoRngCore , Keypair , RandomizedSigner , Signer } ;
77use spki:: {
@@ -23,6 +23,10 @@ use crate::{
2323 time:: Validity ,
2424} ;
2525
26+ pub mod profile;
27+
28+ use self :: profile:: Profile ;
29+
2630/// Error type
2731#[ derive( Debug ) ]
2832#[ non_exhaustive]
@@ -70,180 +74,6 @@ impl From<signature::Error> for Error {
7074
7175type Result < T > = core:: result:: Result < T , Error > ;
7276
73- /// The type of certificate to build
74- #[ derive( Clone , Debug , Eq , PartialEq ) ]
75- pub enum Profile {
76- /// Build a root CA certificate
77- Root ,
78- /// Build an intermediate sub CA certificate
79- SubCA {
80- /// issuer Name,
81- /// represents the name signing the certificate
82- issuer : Name ,
83- /// pathLenConstraint INTEGER (0..MAX) OPTIONAL
84- /// BasicConstraints as defined in [RFC 5280 Section 4.2.1.9].
85- path_len_constraint : Option < u8 > ,
86- } ,
87- /// Build an end certificate
88- Leaf {
89- /// issuer Name,
90- /// represents the name signing the certificate
91- issuer : Name ,
92- /// Usage of the leaf certificate
93- usage : Usage ,
94- /// should the subject key identifier extension be included
95- ///
96- /// From [RFC 5280 Section 4.2.1.2]:
97- /// For end entity certificates, subject key identifiers SHOULD be
98- /// derived from the public key. Two common methods for generating key
99- /// identifiers from the public key are identified above.
100- #[ cfg( feature = "hazmat" ) ]
101- include_subject_key_identifier : bool ,
102- } ,
103- #[ cfg( feature = "hazmat" ) ]
104- /// Opt-out of the default extensions
105- Manual {
106- /// issuer Name,
107- /// represents the name signing the certificate
108- /// A `None` will make it a self-signed certificate
109- issuer : Option < Name > ,
110- } ,
111- }
112-
113- impl Profile {
114- fn get_issuer ( & self , subject : & Name ) -> Name {
115- match self {
116- Profile :: Root => subject. clone ( ) ,
117- Profile :: SubCA { issuer, .. } => issuer. clone ( ) ,
118- Profile :: Leaf { issuer, .. } => issuer. clone ( ) ,
119- #[ cfg( feature = "hazmat" ) ]
120- Profile :: Manual { issuer, .. } => issuer. as_ref ( ) . unwrap_or ( subject) . clone ( ) ,
121- }
122- }
123-
124- fn build_extensions (
125- & self ,
126- spk : SubjectPublicKeyInfoRef < ' _ > ,
127- issuer_spk : SubjectPublicKeyInfoRef < ' _ > ,
128- tbs : & TbsCertificate ,
129- ) -> Result < vec:: Vec < Extension > > {
130- #[ cfg( feature = "hazmat" ) ]
131- // User opted out of default extensions set.
132- if let Profile :: Manual { .. } = self {
133- return Ok ( vec:: Vec :: default ( ) ) ;
134- }
135-
136- let mut extensions: vec:: Vec < Extension > = vec:: Vec :: new ( ) ;
137-
138- match self {
139- #[ cfg( feature = "hazmat" ) ]
140- Profile :: Leaf {
141- include_subject_key_identifier : false ,
142- ..
143- } => { }
144- _ => extensions. push (
145- SubjectKeyIdentifier :: try_from ( spk) ?. to_extension ( & tbs. subject , & extensions) ?,
146- ) ,
147- }
148-
149- // Build Authority Key Identifier
150- match self {
151- Profile :: Root => { }
152- _ => {
153- extensions. push (
154- AuthorityKeyIdentifier :: try_from ( issuer_spk. clone ( ) ) ?
155- . to_extension ( & tbs. subject , & extensions) ?,
156- ) ;
157- }
158- }
159-
160- // Build Basic Contraints extensions
161- extensions. push ( match self {
162- Profile :: Root => BasicConstraints {
163- ca : true ,
164- path_len_constraint : None ,
165- }
166- . to_extension ( & tbs. subject , & extensions) ?,
167- Profile :: SubCA {
168- path_len_constraint,
169- ..
170- } => BasicConstraints {
171- ca : true ,
172- path_len_constraint : * path_len_constraint,
173- }
174- . to_extension ( & tbs. subject , & extensions) ?,
175- Profile :: Leaf { .. } => BasicConstraints {
176- ca : false ,
177- path_len_constraint : None ,
178- }
179- . to_extension ( & tbs. subject , & extensions) ?,
180- #[ cfg( feature = "hazmat" ) ]
181- Profile :: Manual { .. } => unreachable ! ( ) ,
182- } ) ;
183-
184- // Build Key Usage extension
185- match self {
186- Profile :: Root | Profile :: SubCA { .. } => {
187- extensions. push (
188- KeyUsage ( KeyUsages :: KeyCertSign | KeyUsages :: CRLSign )
189- . to_extension ( & tbs. subject , & extensions) ?,
190- ) ;
191- }
192- Profile :: Leaf { usage, .. } => {
193- let key_usage = usage. key_usage ( ) . into ( ) ;
194-
195- extensions. push ( KeyUsage ( key_usage) . to_extension ( & tbs. subject , & extensions) ?) ;
196- }
197- #[ cfg( feature = "hazmat" ) ]
198- Profile :: Manual { .. } => unreachable ! ( ) ,
199- }
200-
201- Ok ( extensions)
202- }
203- }
204-
205- /// [`Usage`] describes the usage of a Leaf certificate.
206- ///
207- /// This is designed in accordance with [ETSI EN 319 412-2 § 4.3.2 Key usage].
208- ///
209- /// The various fields will refer to [RFC 5280 § 4.2.1.3 Key Usage] definitions.
210- ///
211- /// [RFC 5280 § 4.2.1.3 Key Usage]: https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.3
212- /// [ETSI EN 319 412-2 § 4.3.2 Key usage]: https://www.etsi.org/deliver/etsi_en/319400_319499/31941202/02.03.01_60/en_31941202v020301p.pdf#page=11
213- #[ derive( Clone , Debug , PartialEq , Eq ) ]
214- pub enum Usage {
215- /// [`Usage::NonRepudiation`] will set the NonRepudiation (also known as
216- /// contentCommitment) bit of KeyUsage.
217- NonRepudiation ,
218- /// [`Usage::DigitalSignature`] will set the digitalSignature bit.
219- ///
220- /// This is meant to be used in an entity authentication service, a data
221- /// origin authentication service, and/or an integrity service.
222- DigitalSignature ,
223- /// [`Usage::KeyAgreement`] will set the `keyAgreement` bit.
224- ///
225- /// This is meant to be used on Certificates when a Diffie-Hellman key is
226- /// to be used for key management.
227- KeyAgreement ,
228- /// [`Usage::KeyEncipherment`] will set the `keyEncipherment` bit.
229- ///
230- /// This is meant to be used on Certificates when an RSA public
231- /// key is to be used for encrypting a symmetric content-decryption
232- /// key or an asymmetric private key.
233- KeyEncipherment ,
234- }
235-
236- impl Usage {
237- fn key_usage ( & self ) -> KeyUsages {
238- match self {
239- Self :: NonRepudiation => KeyUsages :: NonRepudiation ,
240- Self :: DigitalSignature => KeyUsages :: DigitalSignature ,
241- Self :: KeyAgreement => KeyUsages :: KeyAgreement ,
242- Self :: KeyEncipherment => KeyUsages :: KeyEncipherment ,
243- }
244- }
245- }
246-
24777/// X509 Certificate builder
24878///
24979/// ```
@@ -297,14 +127,17 @@ where
297127 S :: VerifyingKey : EncodePublicKey ,
298128{
299129 /// Creates a new certificate builder
300- pub fn new (
301- profile : Profile ,
130+ pub fn new < P > (
131+ profile : P ,
302132 serial_number : SerialNumber ,
303133 mut validity : Validity ,
304134 subject : Name ,
305135 subject_public_key_info : SubjectPublicKeyInfoOwned ,
306136 cert_signer : & ' s S ,
307- ) -> Result < Self > {
137+ ) -> Result < Self >
138+ where
139+ P : Profile ,
140+ {
308141 let verifying_key = cert_signer. verifying_key ( ) ;
309142 let signer_pub = SubjectPublicKeyInfoOwned :: from_key ( verifying_key) ?;
310143
0 commit comments