parsec_tool/subcommands/
create_csr.rs1use crate::error::{Error, Result, ToolErrorKind};
7use crate::util::sign_message_with_policy;
8use log::error;
9use parsec_client::core::interface::operations::psa_algorithm::{
10 Algorithm, AsymmetricSignature, Hash, SignHash,
11};
12use parsec_client::core::interface::operations::psa_key_attributes::{EccFamily, Type};
13use parsec_client::BasicClient;
14use rcgen::{
15 Certificate, CertificateParams, DistinguishedName, DnType, KeyPair, RcgenError, RemoteKeyPair,
16 SignatureAlgorithm, PKCS_ECDSA_P256_SHA256, PKCS_ECDSA_P384_SHA384, PKCS_RSA_SHA256,
17 PKCS_RSA_SHA384, PKCS_RSA_SHA512,
18};
19use structopt::StructOpt;
20
21#[derive(Debug, StructOpt)]
26pub struct CreateCsr {
27 #[structopt(short = "k", long = "key-name")]
32 key_name: String,
33
34 #[structopt(long = "cn")]
37 common_name: Option<String>,
38
39 #[structopt(long = "l")]
42 locality: Option<String>,
43
44 #[structopt(long = "o")]
47 organization: Option<String>,
48
49 #[structopt(long = "ou")]
52 organizational_unit: Option<String>,
53
54 #[structopt(long = "st")]
56 state: Option<String>,
57
58 #[structopt(long = "c")]
60 country: Option<String>,
61
62 #[structopt(long = "serialNumber")]
64 serial_number: Option<String>,
65
66 #[structopt(long = "san")]
68 subject_alternative_name: Option<Vec<String>>,
69}
70
71struct ParsecRemoteKeyPair {
74 key_name: String,
75 public_key_der: Vec<u8>,
76 parsec_client: BasicClient,
77 rcgen_algorithm: &'static SignatureAlgorithm,
78}
79
80impl CreateCsr {
81 pub fn run(&self, basic_client: BasicClient) -> Result<()> {
83 let public_key = basic_client.psa_export_public_key(&self.key_name)?;
84
85 let rcgen_algorithm = self.get_rcgen_algorithm(&basic_client)?;
86
87 let parsec_key_pair = ParsecRemoteKeyPair {
88 key_name: self.key_name.clone(),
89 public_key_der: public_key,
90 parsec_client: basic_client,
92 rcgen_algorithm,
93 };
94
95 let remote_key_pair = KeyPair::from_remote(Box::new(parsec_key_pair))?;
96
97 let subject_alt_names = match &self.subject_alternative_name {
98 Some(san) => san.to_owned(),
99 None => Vec::new(),
100 };
101
102 let mut dn = DistinguishedName::new();
103
104 if let Some(common_name) = &self.common_name {
105 dn.push(DnType::CommonName, common_name.clone());
106 }
107
108 if let Some(organizational_unit) = &self.organizational_unit {
109 dn.push(DnType::OrganizationalUnitName, organizational_unit.clone());
114 }
115
116 if let Some(organization) = &self.organization {
117 dn.push(DnType::OrganizationName, organization.clone());
118 }
119
120 if let Some(locality) = &self.locality {
121 dn.push(DnType::LocalityName, locality.clone());
122 }
123
124 if let Some(state) = &self.state {
125 dn.push(DnType::StateOrProvinceName, state.clone());
126 }
127
128 if let Some(country) = &self.country {
129 dn.push(DnType::CountryName, country.clone());
130 }
131
132 if let Some(serial_number) = &self.serial_number {
133 dn.push(
137 DnType::CustomDnType(vec![2, 5, 4, 5]),
138 serial_number.clone(),
139 );
140 }
141
142 let mut params = CertificateParams::new(subject_alt_names);
143 params.alg = rcgen_algorithm;
144 params.key_pair = Some(remote_key_pair);
145 params.distinguished_name = dn;
146
147 let cert = Certificate::from_params(params)?;
148
149 let pem_string = cert.serialize_request_pem()?;
150
151 println!("{}", pem_string);
152
153 Ok(())
154 }
155
156 fn get_rcgen_algorithm(
162 &self,
163 basic_client: &BasicClient,
164 ) -> Result<&'static SignatureAlgorithm> {
165 let attributes = basic_client.key_attributes(&self.key_name)?;
166
167 if let Algorithm::AsymmetricSignature(alg) = attributes.policy.permitted_algorithms {
168 match alg {
169 AsymmetricSignature::RsaPkcs1v15Sign { hash_alg } => match hash_alg {
170 SignHash::Specific(Hash::Sha256) => Ok(&PKCS_RSA_SHA256),
171 SignHash::Specific(Hash::Sha384) => Ok(&PKCS_RSA_SHA384),
172 SignHash::Specific(Hash::Sha512) => Ok(&PKCS_RSA_SHA512),
173 SignHash::Any => Ok(&PKCS_RSA_SHA256), _ => {
175 error!("Signing key requires use of hashing algorithm ({:?}), which is not supported for certificate requests.", alg);
177 Err(ToolErrorKind::NotSupported.into())
178 }
179 },
180 AsymmetricSignature::RsaPkcs1v15SignRaw => {
181 error!("Signing key specifies raw signing only, which is not supported for certificate requests.");
183 Err(ToolErrorKind::NotSupported.into())
184 }
185 AsymmetricSignature::RsaPss { .. } => {
186 error!("Signing key specifies RSA PSS scheme, which is not supported for certificate requests.");
187 Err(ToolErrorKind::NotSupported.into())
188 }
189 AsymmetricSignature::Ecdsa { hash_alg } => {
190 if !matches!(
191 attributes.key_type,
192 Type::EccKeyPair {
193 curve_family: EccFamily::SecpR1
194 }
195 ) {
196 error!(
197 "Signing key must use curve family SecpR1 for certificate requests."
198 );
199 return Err(ToolErrorKind::NotSupported.into());
200 };
201
202 match hash_alg {
203 SignHash::Specific(Hash::Sha256) => {
204 if attributes.bits == 256 {
205 Ok(&PKCS_ECDSA_P256_SHA256)
206 } else {
207 error!("Signing key should have strength 256, but actually has strength {}.", attributes.bits);
208 Err(ToolErrorKind::NotSupported.into())
209 }
210 }
211 SignHash::Specific(Hash::Sha384) => {
212 if attributes.bits == 384 {
213 Ok(&PKCS_ECDSA_P384_SHA384)
214 } else {
215 error!("Signing key should have strength 384, but actually has strength {}.", attributes.bits);
216 Err(ToolErrorKind::NotSupported.into())
217 }
218 }
219 SignHash::Any => {
220 match attributes.bits {
221 256 => Ok(&PKCS_ECDSA_P256_SHA256),
222 _ => {
223 error!("Signing keys of strength other than 256-bit not supported without specific hash algorithm.");
226 Err(ToolErrorKind::NotSupported.into())
227 }
228 }
229 }
230 _ => {
231 error!("Signing key requires use of hashing algorithm ({:?}), which is not supported for certificate requests.", alg);
233 Err(ToolErrorKind::NotSupported.into())
234 }
235 }
236 }
237 _ => {
238 error!("The specified key is not supported for certificate requests.");
240 Err(ToolErrorKind::NotSupported.into())
241 }
242 }
243 } else {
244 error!("Specified key is not an asymmetric signing key, which is needed for certificate requests.");
245 Err(ToolErrorKind::WrongKeyAlgorithm.into())
246 }
247 }
248}
249
250impl RemoteKeyPair for ParsecRemoteKeyPair {
251 fn public_key(&self) -> &[u8] {
252 &self.public_key_der
253 }
254
255 fn sign(&self, msg: &[u8]) -> std::result::Result<Vec<u8>, RcgenError> {
256 let signature =
257 sign_message_with_policy(&self.parsec_client, &self.key_name, msg, Some(Hash::Sha256))
258 .map_err(RcgenError::from)?;
259 Ok(signature)
260 }
261
262 fn algorithm(&self) -> &'static SignatureAlgorithm {
263 self.rcgen_algorithm
264 }
265}
266
267impl From<Error> for RcgenError {
268 fn from(_e: Error) -> Self {
269 RcgenError::KeyGenerationUnavailable
275 }
276}