11//! Certificate generation configuration.
22//!
3- use std:: collections:: HashMap ;
3+ use std:: { collections:: HashMap , sync :: LazyLock } ;
44
55use serde:: { Deserialize , Serialize } ;
66
@@ -16,45 +16,73 @@ pub struct Certificates {
1616#[ derive( Debug , Default , Serialize , Deserialize , PartialEq , Eq ) ]
1717#[ serde( default , deny_unknown_fields) ]
1818pub struct CertificateAuthority {
19- /// Enables the export of the private key file
19+ /// Enables the export of the private key file.
2020 pub export_key : bool ,
2121
22- /// Certificates that are signed by this CA
22+ /// Certificates that are signed by this CA.
2323 #[ serde( skip_serializing_if = "HashMap::is_empty" ) ]
2424 pub certificates : HashMap < String , CertificateTypes > ,
2525}
2626
27- /// A certificate used for client authentication
27+ /// A certificate used for client authentication.
2828#[ derive( Debug , Serialize , Deserialize , PartialEq , Eq ) ]
2929#[ serde( default , deny_unknown_fields) ]
3030pub struct Client {
31- /// Enables the export of the private key file
31+ /// Enables the export of the private key file.
3232 pub export_key : bool ,
3333}
3434
35- /// A certificate used for server authentication
35+ /// A certificate used for server authentication.
3636#[ derive( Debug , Serialize , Deserialize , PartialEq , Eq ) ]
3737#[ serde( default , deny_unknown_fields) ]
3838pub struct Server {
39- /// Enables the export of the private key file
39+ /// Enables the export of the private key file.
4040 pub export_key : bool ,
4141}
4242
43- /// All kinds of different certificates
43+ /// All kinds of different certificates.
4444#[ derive( Debug , Serialize , Deserialize , PartialEq , Eq ) ]
4545#[ serde( tag = "type" , rename_all = "lowercase" ) ]
4646pub enum CertificateTypes {
47- /// A certificate that acts as a Certificate Authority
47+ /// A certificate that acts as a Certificate Authority.
4848 #[ serde( alias = "ca" ) ]
4949 CertificateAuthority ( CertificateAuthority ) ,
5050
51- /// A certificate for client authentication
51+ /// A certificate for client authentication.
5252 Client ( Client ) ,
5353
54- /// A certificate for server authentication
54+ /// A certificate for server authentication.
5555 Server ( Server ) ,
5656}
5757
58+ impl CertificateTypes {
59+ /// Should the private key be exported or not
60+ pub fn export_key ( & self ) -> bool {
61+ match self {
62+ CertificateTypes :: CertificateAuthority ( certificate_authority) => {
63+ certificate_authority. export_key
64+ }
65+ CertificateTypes :: Client ( client) => client. export_key ,
66+ CertificateTypes :: Server ( server) => server. export_key ,
67+ }
68+ }
69+
70+ /// Certificates issued by this certificate.
71+ pub fn certificates ( & self ) -> & HashMap < String , CertificateTypes > {
72+ match self {
73+ CertificateTypes :: CertificateAuthority ( certificate_authority) => {
74+ & certificate_authority. certificates
75+ }
76+ CertificateTypes :: Client ( _client) => & NO_CERTIFICATES ,
77+ CertificateTypes :: Server ( _server) => & NO_CERTIFICATES ,
78+ }
79+ }
80+ }
81+
82+ /// Is used to provide a reference to an empty HashMap.
83+ /// The [`LazyLock`] is required as a HashMap::new is not usable in const expressions.
84+ static NO_CERTIFICATES : LazyLock < HashMap < String , CertificateTypes > > = LazyLock :: new ( HashMap :: new) ;
85+
5886impl Default for Client {
5987 fn default ( ) -> Self {
6088 Self { export_key : true }
@@ -67,11 +95,63 @@ impl Default for Server {
6795 }
6896}
6997
98+ /// Fixtures for testing certificate generation.
99+ #[ cfg( any( test, feature = "fixtures" ) ) ]
100+ pub mod fixtures {
101+ use super :: * ;
102+
103+ /// Creates a certificate authority and a server and client certificated that are issued by it.
104+ pub fn certificate_ca_with_client ( ) -> Certificates {
105+ let certs = Certificates {
106+ certificates : HashMap :: from ( [ ( "ca" . to_string ( ) , ca_with_client ( ) ) ] ) ,
107+ } ;
108+ certs
109+ }
110+
111+ /// Creates a certificate of type ca with a client cert.
112+ pub fn ca_with_client ( ) -> CertificateTypes {
113+ CertificateTypes :: CertificateAuthority ( CertificateAuthority {
114+ certificates : HashMap :: from ( [ (
115+ "client" . to_string ( ) ,
116+ CertificateTypes :: Client ( Client :: default ( ) ) ,
117+ ) ] ) ,
118+ ..Default :: default ( )
119+ } )
120+ }
121+
122+ /// Creates a client certificate.
123+ pub fn certificate_client ( ) -> Certificates {
124+ let certs = Certificates {
125+ certificates : HashMap :: from ( [ (
126+ "client" . to_string ( ) ,
127+ CertificateTypes :: Client ( Client :: default ( ) ) ,
128+ ) ] ) ,
129+ } ;
130+ certs
131+ }
132+
133+ /// Creates a certificate of type client.
134+ pub fn client ( ) -> CertificateTypes {
135+ CertificateTypes :: Client ( Client :: default ( ) )
136+ }
137+
138+ /// Creates a certificate authority without any other certificates.
139+ pub fn certificate_ca ( ) -> Certificates {
140+ let certs = Certificates {
141+ certificates : HashMap :: from ( [ (
142+ "ca" . to_string ( ) ,
143+ CertificateTypes :: CertificateAuthority ( CertificateAuthority :: default ( ) ) ,
144+ ) ] ) ,
145+ } ;
146+ certs
147+ }
148+ }
149+
70150#[ cfg( test) ]
71151mod tests {
72- use serde_json:: json;
73-
74152 use super :: * ;
153+ use fixtures:: certificate_ca_with_client;
154+ use serde_json:: json;
75155
76156 fn get_ca ( cert : & CertificateTypes ) -> & CertificateAuthority {
77157 assert ! ( matches!( cert, CertificateTypes :: CertificateAuthority ( _) ) ) ;
@@ -139,18 +219,7 @@ mod tests {
139219
140220 #[ test]
141221 fn should_serde_roundtrip ( ) {
142- let certs = Certificates {
143- certificates : HashMap :: from_iter ( [ (
144- "my-ca" . to_string ( ) ,
145- CertificateTypes :: CertificateAuthority ( CertificateAuthority {
146- export_key : true ,
147- certificates : HashMap :: from_iter ( [ (
148- "client" . to_string ( ) ,
149- CertificateTypes :: Client ( Client { export_key : true } ) ,
150- ) ] ) ,
151- } ) ,
152- ) ] ) ,
153- } ;
222+ let certs = certificate_ca_with_client ( ) ;
154223
155224 let serialized = serde_json:: to_string ( & certs) . unwrap ( ) ;
156225 let deserialized: Certificates = serde_json:: from_str ( & serialized) . unwrap ( ) ;
@@ -202,5 +271,15 @@ mod tests {
202271
203272 assert ! ( matches!( ca, CertificateTypes :: CertificateAuthority ( _) ) )
204273 }
274+
275+ #[ test]
276+ fn should_serde_roundtrip ( ) {
277+ let certs = certificate_ca_with_client ( ) ;
278+
279+ let serialized = serde_yaml:: to_string ( & certs) . unwrap ( ) ;
280+ let deserialized: Certificates = serde_yaml:: from_str ( & serialized) . unwrap ( ) ;
281+
282+ assert_eq ! ( deserialized, certs)
283+ }
205284 }
206285}
0 commit comments