use crate::error::{Result, ToolErrorKind};
use log::error;
use oid::prelude::*;
use parsec_client::core::interface::operations::psa_key_attributes::{EccFamily, Type};
use parsec_client::BasicClient;
use picky_asn1::bit_string::BitString;
use picky_asn1_x509::{
AlgorithmIdentifier, EcParameters, PublicKey, RsaPublicKey, SubjectPublicKeyInfo,
};
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
pub struct ExportPublicKey {
#[structopt(short = "k", long = "key-name")]
key_name: String,
#[structopt(long = "pkcs1")]
pkcs1: bool,
}
impl ExportPublicKey {
pub fn run(&self, basic_client: BasicClient) -> Result<()> {
let mut tag = String::from("PUBLIC KEY");
let mut psa_public_key = basic_client.psa_export_public_key(&self.key_name)?;
let psa_key_attributes = basic_client.key_attributes(&self.key_name)?;
match psa_key_attributes.key_type {
Type::RsaKeyPair | Type::RsaPublicKey => {
if self.pkcs1 {
tag = String::from("RSA PUBLIC KEY");
} else {
psa_public_key = picky_asn1_der::to_vec(&SubjectPublicKeyInfo {
algorithm: AlgorithmIdentifier::new_rsa_encryption(),
subject_public_key: PublicKey::Rsa(
picky_asn1_der::from_bytes::<RsaPublicKey>(&psa_public_key)
.map_err(|_| {
error!("Could not deserialise RSA key");
ToolErrorKind::IncorrectData
})?
.into(),
),
})
.map_err(|_| {
error!("Could not serialise RSA key");
ToolErrorKind::IncorrectData
})?;
}
}
Type::EccKeyPair {
curve_family: curve,
}
| Type::EccPublicKey {
curve_family: curve,
} => {
if self.pkcs1 {
error!("PKCS1 format doesn't support ECC keys");
return Err(ToolErrorKind::WrongKeyAlgorithm.into());
} else {
psa_public_key = picky_asn1_der::to_vec(&SubjectPublicKeyInfo {
algorithm: AlgorithmIdentifier::new_elliptic_curve(
EcParameters::NamedCurve(
curve_oid(curve, psa_key_attributes.bits)?.into(),
),
),
subject_public_key: PublicKey::Ec(
BitString::with_bytes(psa_public_key).into(),
),
})
.map_err(|_| {
error!("Could not serialise ECC key");
ToolErrorKind::IncorrectData
})?;
}
}
_ => {
error!("Unsupported type of key");
return Err(ToolErrorKind::NotSupported.into());
}
};
let pem_encoded = pem::encode_config(
&pem::Pem {
tag,
contents: psa_public_key,
},
pem::EncodeConfig {
line_ending: pem::LineEnding::LF,
},
);
print!("{}", pem_encoded);
Ok(())
}
}
fn curve_oid(curve: EccFamily, key_bits: usize) -> Result<ObjectIdentifier> {
let curve_oid = match curve {
EccFamily::SecpR1 => match key_bits {
192 => picky_asn1_x509::oids::secp192r1(),
224 => picky_asn1_x509::oids::secp224r1(),
256 => picky_asn1_x509::oids::secp256r1(),
384 => picky_asn1_x509::oids::secp384r1(),
521 => picky_asn1_x509::oids::secp521r1(),
_ => return print_error(curve, key_bits),
},
EccFamily::SecpK1 => match key_bits {
192 => ObjectIdentifier::try_from("1.3.132.0.31").unwrap(),
224 => ObjectIdentifier::try_from("1.3.132.0.32").unwrap(),
256 => ObjectIdentifier::try_from("1.3.132.0.10").unwrap(),
_ => return print_error(curve, key_bits),
},
EccFamily::SectK1 => match key_bits {
233 => picky_asn1_x509::oids::sect233k1(),
283 => picky_asn1_x509::oids::sect283k1(),
409 => picky_asn1_x509::oids::sect409k1(),
571 => picky_asn1_x509::oids::sect571k1(),
_ => return print_error(curve, key_bits),
},
EccFamily::SectR1 => match key_bits {
233 => picky_asn1_x509::oids::sect233r1(),
283 => picky_asn1_x509::oids::sect283r1(),
409 => picky_asn1_x509::oids::sect409r1(),
571 => picky_asn1_x509::oids::sect571r1(),
_ => return print_error(curve, key_bits),
},
_ => {
error!("Unsupported Ecc family \"{}\"", curve);
return Err(ToolErrorKind::NotSupported.into());
}
};
Ok(curve_oid)
}
fn print_error(curve: EccFamily, key_bits: usize) -> Result<ObjectIdentifier> {
error!(
"Unsupported number of bits {} for Ecc family \"{}\"",
key_bits, curve
);
Err(ToolErrorKind::NotSupported.into())
}