feat: v1.12.6
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use crate::keyutil::{parse_key_uri, KeyUri, KeyUsage};
|
||||
use crate::util::base64_encode;
|
||||
use crate::util::{base64_decode, base64_encode};
|
||||
use crate::yubikeyutil::find_key_or_error;
|
||||
use crate::{cmdutil, ecdsautil, hmacutil, seutil, util, yubikeyutil};
|
||||
use clap::{App, ArgMatches, SubCommand};
|
||||
@@ -8,7 +8,10 @@ use rust_util::util_clap::{Command, CommandError};
|
||||
use rust_util::XResult;
|
||||
use serde_json::Value;
|
||||
use std::collections::BTreeMap;
|
||||
use rsa::RsaPrivateKey;
|
||||
use spki::EncodePublicKey;
|
||||
use x509_parser::parse_x509_certificate;
|
||||
use crate::pivutil::ToStr;
|
||||
|
||||
pub struct CommandImpl;
|
||||
|
||||
@@ -68,21 +71,31 @@ fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>) -> XResult<Vec<u
|
||||
simple_error!("Slot {} not found", key.slot)
|
||||
}
|
||||
KeyUri::YubikeyHmacEncSoftKey(key) => {
|
||||
let private_key = hmacutil::try_hmac_decrypt_to_string(&key.hmac_enc_private_key)?;
|
||||
let p256_public_key = ecdsautil::parse_p256_private_key_to_public_key(&private_key).ok();
|
||||
let p384_public_key = ecdsautil::parse_p384_private_key_to_public_key(&private_key).ok();
|
||||
let p521_public_key = ecdsautil::parse_p521_private_key_to_public_key(&private_key).ok();
|
||||
if key.algorithm.is_ecc() {
|
||||
let private_key = hmacutil::try_hmac_decrypt_to_string(&key.hmac_enc_private_key)?;
|
||||
let p256_public_key = ecdsautil::parse_p256_private_key_to_public_key(&private_key).ok();
|
||||
let p384_public_key = ecdsautil::parse_p384_private_key_to_public_key(&private_key).ok();
|
||||
let p521_public_key = ecdsautil::parse_p521_private_key_to_public_key(&private_key).ok();
|
||||
|
||||
if let Some(p256_public_key) = p256_public_key {
|
||||
return Ok(p256_public_key);
|
||||
if let Some(p256_public_key) = p256_public_key {
|
||||
return Ok(p256_public_key);
|
||||
}
|
||||
if let Some(p384_public_key) = p384_public_key {
|
||||
return Ok(p384_public_key);
|
||||
}
|
||||
if let Some(p521_public_key) = p521_public_key {
|
||||
return Ok(p521_public_key);
|
||||
}
|
||||
simple_error!("Invalid hmac enc private key")
|
||||
} else if key.algorithm.is_rsa() {
|
||||
use rsa::pkcs8::DecodePrivateKey;
|
||||
let private_key = hmacutil::try_hmac_decrypt_to_string(&key.hmac_enc_private_key)?;
|
||||
let private_key_der = base64_decode(&private_key)?;
|
||||
let rsa_private_key = RsaPrivateKey::from_pkcs8_der(&private_key_der)?;
|
||||
Ok(rsa_private_key.to_public_key().to_public_key_der()?.to_vec())
|
||||
} else {
|
||||
simple_error!("Invalid algorithm: {}", key.algorithm.to_str())
|
||||
}
|
||||
if let Some(p384_public_key) = p384_public_key {
|
||||
return Ok(p384_public_key);
|
||||
}
|
||||
if let Some(p521_public_key) = p521_public_key {
|
||||
return Ok(p521_public_key);
|
||||
}
|
||||
simple_error!("Invalid hmac enc private key")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
use crate::cmd_sign_jwt::digest_by_jwt_algorithm;
|
||||
use crate::keyutil::{parse_key_uri, KeyUri, KeyUsage, YubikeyPivKey};
|
||||
use crate::cmd_sign_jwt_soft::{convert_jwt_algorithm_to_ecdsa_algorithm, parse_ecdsa_private_key};
|
||||
use crate::ecdsautil::EcdsaSignType;
|
||||
use crate::keyutil::{parse_key_uri, KeyAlgorithmId, KeyUri, KeyUsage, YubikeyPivKey};
|
||||
use crate::pivutil::ToStr;
|
||||
use crate::rsautil::RsaSignAlgorithm;
|
||||
use crate::util::{base64_decode, base64_encode};
|
||||
use crate::{cmdutil, ecdsautil, hmacutil, pivutil, seutil, util, yubikeyutil};
|
||||
use crate::{cmdutil, ecdsautil, hmacutil, pivutil, rsautil, seutil, util, yubikeyutil};
|
||||
use clap::{App, ArgMatches, SubCommand};
|
||||
use jwt::AlgorithmType;
|
||||
use rsa::RsaPrivateKey;
|
||||
use rust_util::util_clap::{Command, CommandError};
|
||||
use rust_util::XResult;
|
||||
use serde_json::Value;
|
||||
use std::collections::BTreeMap;
|
||||
use yubikey::piv::{sign_data, AlgorithmId};
|
||||
use crate::cmd_sign_jwt_soft::{convert_jwt_algorithm_to_ecdsa_algorithm, parse_ecdsa_private_key};
|
||||
use crate::ecdsautil::EcdsaSignType;
|
||||
use yubikey::piv::sign_data;
|
||||
|
||||
pub struct CommandImpl;
|
||||
|
||||
@@ -79,22 +81,45 @@ fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
|
||||
);
|
||||
}
|
||||
|
||||
let algorithm = opt_value_result!(
|
||||
KeyAlgorithmId::to_algorithm_id(key.algorithm),
|
||||
"Yubikey not supported algorithm: {}",
|
||||
key.algorithm.to_str()
|
||||
);
|
||||
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, &message_bytes)?;
|
||||
let signed_data = opt_result!(
|
||||
sign_data(&mut yk, &raw_in, key.algorithm, key.slot),
|
||||
sign_data(&mut yk, &raw_in, algorithm, key.slot),
|
||||
"Sign YubiKey failed: {}"
|
||||
);
|
||||
Ok(signed_data.to_vec())
|
||||
}
|
||||
KeyUri::YubikeyHmacEncSoftKey(key) => {
|
||||
let private_key = hmacutil::try_hmac_decrypt_to_string(&key.hmac_enc_private_key)?;
|
||||
let (jwt_algorithm, private_key_d) = parse_ecdsa_private_key(&private_key)?;
|
||||
if key.algorithm.is_ecc() {
|
||||
let private_key = hmacutil::try_hmac_decrypt_to_string(&key.hmac_enc_private_key)?;
|
||||
let (jwt_algorithm, private_key_d) = parse_ecdsa_private_key(&private_key)?;
|
||||
|
||||
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, &message_bytes)?;
|
||||
let ecdsa_algorithm = convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm)?;
|
||||
let signed_data = ecdsautil::ecdsa_sign(ecdsa_algorithm, &private_key_d, &raw_in, EcdsaSignType::Der)?;
|
||||
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, &message_bytes)?;
|
||||
let ecdsa_algorithm = convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm)?;
|
||||
let signed_data = ecdsautil::ecdsa_sign(
|
||||
ecdsa_algorithm,
|
||||
&private_key_d,
|
||||
&raw_in,
|
||||
EcdsaSignType::Der,
|
||||
)?;
|
||||
|
||||
Ok(signed_data)
|
||||
Ok(signed_data)
|
||||
} else if key.algorithm.is_rsa() {
|
||||
use rsa::pkcs8::DecodePrivateKey;
|
||||
let private_key = hmacutil::try_hmac_decrypt_to_string(&key.hmac_enc_private_key)?;
|
||||
let private_key_der = base64_decode(&private_key)?;
|
||||
let rsa_private_key = RsaPrivateKey::from_pkcs8_der(&private_key_der)?;
|
||||
|
||||
let rsa_sign_algorithm =
|
||||
opt_value_result!(RsaSignAlgorithm::from_str(alg), "Invalid --alg: {}", alg);
|
||||
rsautil::sign(&rsa_private_key, rsa_sign_algorithm, &message_bytes)
|
||||
} else {
|
||||
simple_error!("Invalid algorithm: {}", key.algorithm.to_str())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,20 +128,23 @@ fn get_jwt_algorithm(key: &YubikeyPivKey, alg: &str) -> XResult<AlgorithmType> {
|
||||
let jwt_algorithm = match alg {
|
||||
"ES256" => AlgorithmType::Es256,
|
||||
"ES384" => AlgorithmType::Es384,
|
||||
"ES512" => AlgorithmType::Es512,
|
||||
"RS256" => AlgorithmType::Rs256,
|
||||
_ => return simple_error!("Invalid alg: {}", alg),
|
||||
};
|
||||
if key.algorithm == AlgorithmId::Rsa1024 {
|
||||
if key.algorithm == KeyAlgorithmId::Rsa1024 {
|
||||
return simple_error!("Invalid algorithm: RSA1024");
|
||||
}
|
||||
let is_p256_mismatch =
|
||||
key.algorithm == AlgorithmId::EccP256 && jwt_algorithm != AlgorithmType::Es256;
|
||||
key.algorithm == KeyAlgorithmId::EccP256 && jwt_algorithm != AlgorithmType::Es256;
|
||||
let is_p384_mismatch =
|
||||
key.algorithm == AlgorithmId::EccP384 && jwt_algorithm != AlgorithmType::Es384;
|
||||
key.algorithm == KeyAlgorithmId::EccP384 && jwt_algorithm != AlgorithmType::Es384;
|
||||
let is_p521_mismatch =
|
||||
key.algorithm == KeyAlgorithmId::EccP521 && jwt_algorithm != AlgorithmType::Es512;
|
||||
let is_rsa_mismatch =
|
||||
key.algorithm == AlgorithmId::Rsa2048 && jwt_algorithm != AlgorithmType::Rs256;
|
||||
key.algorithm == KeyAlgorithmId::Rsa2048 && jwt_algorithm != AlgorithmType::Rs256;
|
||||
|
||||
if is_p256_mismatch || is_p384_mismatch || is_rsa_mismatch {
|
||||
if is_p256_mismatch || is_p384_mismatch || is_p521_mismatch || is_rsa_mismatch {
|
||||
return simple_error!("Invalid algorithm: {} vs {}", key.algorithm.to_str(), alg);
|
||||
}
|
||||
Ok(jwt_algorithm)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use crate::ecdsautil::EcdsaAlgorithm;
|
||||
use crate::keychain::{KeychainKey, KeychainKeyValue};
|
||||
use crate::{cmdutil, ecdsautil, hmacutil, util, yubikeyutil};
|
||||
use crate::keyutil::{KeyAlgorithmId, KeyUri, YubikeyHmacEncSoftKey};
|
||||
use crate::util::base64_encode;
|
||||
use crate::{cmdutil, ecdsautil, hmacutil, rsautil, util, yubikeyutil};
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rust_util::util_clap::{Command, CommandError};
|
||||
use std::collections::BTreeMap;
|
||||
use yubikey::piv::AlgorithmId;
|
||||
use crate::ecdsautil::EcdsaAlgorithm;
|
||||
use crate::keyutil::{KeyUri, YubikeyHmacEncSoftKey};
|
||||
use crate::util::base64_encode;
|
||||
|
||||
pub struct CommandImpl;
|
||||
|
||||
@@ -23,7 +22,7 @@ impl Command for CommandImpl {
|
||||
.long("type")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.help("Key type (e.g. p256, p384, p521)"),
|
||||
.help("Key type (e.g. p256, p384, p521, rsa1024, rsa2048)"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("with-hmac-encrypt")
|
||||
@@ -49,20 +48,26 @@ impl Command for CommandImpl {
|
||||
}
|
||||
|
||||
let ecdsa_algorithm = match key_type.as_str() {
|
||||
"p256" => EcdsaAlgorithm::P256,
|
||||
"p384" => EcdsaAlgorithm::P384,
|
||||
"p521" => EcdsaAlgorithm::P521,
|
||||
_ => {
|
||||
return simple_error!("Key type must be p256 or p384");
|
||||
}
|
||||
"p256" => Some(EcdsaAlgorithm::P256),
|
||||
"p384" => Some(EcdsaAlgorithm::P384),
|
||||
"p521" => Some(EcdsaAlgorithm::P521),
|
||||
_ => None,
|
||||
};
|
||||
let rsa_bit_size: Option<usize> = match key_type.as_str() {
|
||||
"rsa1024" => Some(1024),
|
||||
"rsa2048" => Some(2048),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let (pkcs8_base64,
|
||||
secret_key_pem,
|
||||
public_key_pem,
|
||||
public_key_der,
|
||||
jwk_ec_key
|
||||
) = ecdsautil::generate_ecdsa_keypair(ecdsa_algorithm)?;
|
||||
let (
|
||||
pkcs8_base64, secret_key_pem, public_key_pem, public_key_der, jwk_key
|
||||
) = if let Some(ecdsa_algorithm) = ecdsa_algorithm {
|
||||
ecdsautil::generate_ecdsa_keypair(ecdsa_algorithm)?
|
||||
} else if let Some(rsa_bit_size) = rsa_bit_size {
|
||||
rsautil::generate_rsa_keypair(rsa_bit_size)?
|
||||
} else {
|
||||
return simple_error!("Unsupported key type: {}", key_type);
|
||||
};
|
||||
|
||||
let (pkcs8_base64, secret_key_pem) = if with_hmac_encrypt {
|
||||
(
|
||||
@@ -80,7 +85,7 @@ impl Command for CommandImpl {
|
||||
pkcs8_base64: pkcs8_base64.clone(),
|
||||
secret_key_pem: secret_key_pem.clone(),
|
||||
public_key_pem: public_key_pem.clone(),
|
||||
public_key_jwk: jwk_ec_key.to_string(),
|
||||
public_key_jwk: jwk_key.clone(),
|
||||
};
|
||||
let keychain_key_value_json = serde_json::to_string(&keychain_key_value)?;
|
||||
|
||||
@@ -98,18 +103,24 @@ impl Command for CommandImpl {
|
||||
json.insert("private_key_base64", pkcs8_base64.clone());
|
||||
json.insert("private_key_pem", secret_key_pem);
|
||||
let algorithm_id = match key_type.as_str() {
|
||||
"p256" => Some(AlgorithmId::EccP256),
|
||||
"p384" => Some(AlgorithmId::EccP384),
|
||||
"p256" => Some(KeyAlgorithmId::EccP256),
|
||||
"p384" => Some(KeyAlgorithmId::EccP384),
|
||||
"p521" => Some(KeyAlgorithmId::EccP521),
|
||||
"rsa1024" => Some(KeyAlgorithmId::Rsa1024),
|
||||
"rsa2048" => Some(KeyAlgorithmId::Rsa2048),
|
||||
_ => None,
|
||||
};
|
||||
if let (true, Some(algorithm_id)) = (with_hmac_encrypt, algorithm_id) {
|
||||
let yk = yubikeyutil::open_yubikey()?;
|
||||
let yubikey_hmac_enc_soft_key = YubikeyHmacEncSoftKey {
|
||||
key_name: format!("yubikey{}-{}", yk.version().major, yk.serial().0),
|
||||
key_name: format!("yubikey{}-{}", yk.version().major, yk.serial().0),
|
||||
algorithm: algorithm_id,
|
||||
hmac_enc_private_key: pkcs8_base64,
|
||||
};
|
||||
json.insert("key_uri", KeyUri::YubikeyHmacEncSoftKey(yubikey_hmac_enc_soft_key).to_string());
|
||||
json.insert(
|
||||
"key_uri",
|
||||
KeyUri::YubikeyHmacEncSoftKey(yubikey_hmac_enc_soft_key).to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(keychain_key_uri) => {
|
||||
@@ -118,7 +129,7 @@ impl Command for CommandImpl {
|
||||
}
|
||||
json.insert("public_key_pem", public_key_pem);
|
||||
json.insert("public_key_base64", public_key_base64);
|
||||
json.insert("public_key_jwk", jwk_ec_key.to_string());
|
||||
json.insert("public_key_jwk", jwk_key);
|
||||
|
||||
util::print_pretty_json(&json);
|
||||
} else {
|
||||
@@ -133,7 +144,7 @@ impl Command for CommandImpl {
|
||||
}
|
||||
information!("Public key PEM:\n{}", public_key_pem);
|
||||
information!("Public key Base64:\n{}\n", public_key_base64);
|
||||
information!("Public key JWK:\n{}", jwk_ec_key.to_string());
|
||||
information!("Public key JWK:\n{}", jwk_key);
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
|
||||
@@ -10,7 +10,7 @@ use yubikey::Key;
|
||||
use yubikey::piv::{AlgorithmId, metadata};
|
||||
|
||||
use crate::{cmdutil, pivutil, util, yubikeyutil};
|
||||
use crate::keyutil::{KeyUri, YubikeyPivKey};
|
||||
use crate::keyutil::{KeyAlgorithmId, KeyUri, YubikeyPivKey};
|
||||
use crate::pivutil::{get_algorithm_id_by_certificate, slot_equals, ToStr};
|
||||
use crate::pkiutil::bytes_to_pem;
|
||||
use crate::sshutil::SshVecWriter;
|
||||
@@ -106,7 +106,7 @@ impl Command for CommandImpl {
|
||||
|
||||
let yubikey_piv_key = YubikeyPivKey {
|
||||
key_name: format!("yubikey{}-{}", yk.version().major, yk.serial().0),
|
||||
algorithm: algorithm_id,
|
||||
algorithm: KeyAlgorithmId::from_algorithm_id(algorithm_id),
|
||||
slot: slot_id,
|
||||
};
|
||||
json.insert("key_uri", KeyUri::YubikeyPivKey(yubikey_piv_key).to_string());
|
||||
|
||||
@@ -133,6 +133,7 @@ pub fn digest_by_jwt_algorithm(jwt_algorithm: AlgorithmType, tobe_signed: &[u8])
|
||||
}
|
||||
AlgorithmType::Es256 => digestutil::sha256_bytes(tobe_signed),
|
||||
AlgorithmType::Es384 => digestutil::sha384_bytes(tobe_signed),
|
||||
AlgorithmType::Es512 => digestutil::sha512_bytes(tobe_signed),
|
||||
_ => return simple_error!("SHOULD NOT HAPPEN: {:?}", jwt_algorithm),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ use ecdsa::elliptic_curve::pkcs8::LineEnding;
|
||||
use ecdsa::VerifyingKey;
|
||||
use p256::NistP256;
|
||||
use p256::ecdsa::signature::hazmat::PrehashVerifier;
|
||||
use p256::elliptic_curve::JwkEcKey;
|
||||
use p384::NistP384;
|
||||
use p256::pkcs8::EncodePrivateKey;
|
||||
use p521::NistP521;
|
||||
@@ -78,12 +77,12 @@ macro_rules! generate_inner_ecdsa_keypair {
|
||||
let secret_key_pem = secret_key.to_pkcs8_pem(LineEnding::LF)?.to_string();
|
||||
let public_key_pem = secret_key.public_key().to_public_key_pem(LineEnding::LF)?;
|
||||
let public_key_der = secret_key.public_key().to_public_key_der()?.to_vec();
|
||||
let jwk_ec_key = secret_key.public_key().to_jwk();
|
||||
let jwk_ec_key = secret_key.public_key().to_jwk().to_string();
|
||||
Ok((secret_key_der_base64, secret_key_pem, public_key_pem, public_key_der, jwk_ec_key))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generate_ecdsa_keypair(algo: EcdsaAlgorithm) -> XResult<(String, String, String, Vec<u8>, JwkEcKey)> {
|
||||
pub fn generate_ecdsa_keypair(algo: EcdsaAlgorithm) -> XResult<(String, String, String, Vec<u8>, String)> {
|
||||
match algo {
|
||||
EcdsaAlgorithm::P256 => generate_inner_ecdsa_keypair!(p256),
|
||||
EcdsaAlgorithm::P384 => generate_inner_ecdsa_keypair!(p384),
|
||||
|
||||
118
src/keyutil.rs
118
src/keyutil.rs
@@ -1,7 +1,7 @@
|
||||
use crate::pivutil::{FromStr, ToStr};
|
||||
use regex::Regex;
|
||||
use rust_util::XResult;
|
||||
use yubikey::piv::{AlgorithmId, SlotId};
|
||||
use crate::pivutil::{ToStr, FromStr};
|
||||
|
||||
// reference: https://git.hatter.ink/hatter/card-cli/issues/6
|
||||
#[derive(Debug)]
|
||||
@@ -55,6 +55,78 @@ impl ToString for KeyUri {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum KeyAlgorithmId {
|
||||
Rsa1024,
|
||||
Rsa2048,
|
||||
EccP256,
|
||||
EccP384,
|
||||
EccP521,
|
||||
}
|
||||
|
||||
impl KeyAlgorithmId {
|
||||
pub fn from_algorithm_id(algorithm_id: AlgorithmId) -> Self {
|
||||
match algorithm_id {
|
||||
AlgorithmId::Rsa1024 => Self::Rsa1024,
|
||||
AlgorithmId::Rsa2048 => Self::Rsa2048,
|
||||
AlgorithmId::EccP256 => Self::EccP256,
|
||||
AlgorithmId::EccP384 => Self::EccP384,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_algorithm_id(self) -> Option<AlgorithmId> {
|
||||
match self {
|
||||
KeyAlgorithmId::Rsa1024 => Some(AlgorithmId::Rsa1024),
|
||||
KeyAlgorithmId::Rsa2048 => Some(AlgorithmId::Rsa2048),
|
||||
KeyAlgorithmId::EccP256 => Some(AlgorithmId::EccP256),
|
||||
KeyAlgorithmId::EccP384 => Some(AlgorithmId::EccP384),
|
||||
KeyAlgorithmId::EccP521 => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_rsa(&self) -> bool {
|
||||
match self {
|
||||
KeyAlgorithmId::Rsa1024 | KeyAlgorithmId::Rsa2048 => true,
|
||||
KeyAlgorithmId::EccP256 | KeyAlgorithmId::EccP384 | KeyAlgorithmId::EccP521 => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ecc(&self) -> bool {
|
||||
match self {
|
||||
KeyAlgorithmId::Rsa1024 | KeyAlgorithmId::Rsa2048 => false,
|
||||
KeyAlgorithmId::EccP256 | KeyAlgorithmId::EccP384 | KeyAlgorithmId::EccP521 => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for KeyAlgorithmId {
|
||||
fn from_str(s: &str) -> Option<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match s {
|
||||
"rsa1024" => Some(KeyAlgorithmId::Rsa1024),
|
||||
"rsa2048" => Some(KeyAlgorithmId::Rsa2048),
|
||||
"p256" => Some(KeyAlgorithmId::EccP256),
|
||||
"p384" => Some(KeyAlgorithmId::EccP384),
|
||||
"p521" => Some(KeyAlgorithmId::EccP521),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToStr for KeyAlgorithmId {
|
||||
fn to_str(&self) -> &str {
|
||||
match self {
|
||||
KeyAlgorithmId::Rsa1024 => "rsa1024",
|
||||
KeyAlgorithmId::Rsa2048 => "rsa2048",
|
||||
KeyAlgorithmId::EccP256 => "p256",
|
||||
KeyAlgorithmId::EccP384 => "p384",
|
||||
KeyAlgorithmId::EccP521 => "p521",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum KeyUsage {
|
||||
Any,
|
||||
@@ -78,8 +150,9 @@ impl ToString for KeyUsage {
|
||||
match self {
|
||||
KeyUsage::Any => "*",
|
||||
KeyUsage::Singing => "signing",
|
||||
KeyUsage::KeyAgreement => "key_agreement"
|
||||
}.to_string()
|
||||
KeyUsage::KeyAgreement => "key_agreement",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +168,7 @@ pub struct SecureEnclaveKey {
|
||||
#[derive(Debug)]
|
||||
pub struct YubikeyPivKey {
|
||||
pub key_name: String,
|
||||
pub algorithm: AlgorithmId,
|
||||
pub algorithm: KeyAlgorithmId,
|
||||
pub slot: SlotId,
|
||||
}
|
||||
|
||||
@@ -103,7 +176,7 @@ pub struct YubikeyPivKey {
|
||||
#[derive(Debug)]
|
||||
pub struct YubikeyHmacEncSoftKey {
|
||||
pub key_name: String,
|
||||
pub algorithm: AlgorithmId,
|
||||
pub algorithm: KeyAlgorithmId,
|
||||
pub hmac_enc_private_key: String,
|
||||
}
|
||||
|
||||
@@ -142,8 +215,16 @@ pub fn parse_key_uri(key_uri: &str) -> XResult<KeyUri> {
|
||||
if "" != usage {
|
||||
return simple_error!("Key uri's usage must be empty.");
|
||||
}
|
||||
let algorithm = opt_value_result!(AlgorithmId::from_str(algorithm), "Invalid algorithm id: {}", algorithm);
|
||||
let slot = opt_value_result!(SlotId::from_str(left_part), "Invalid slot id: {}", left_part);
|
||||
let algorithm = opt_value_result!(
|
||||
KeyAlgorithmId::from_str(algorithm),
|
||||
"Invalid algorithm id: {}",
|
||||
algorithm
|
||||
);
|
||||
let slot = opt_value_result!(
|
||||
SlotId::from_str(left_part),
|
||||
"Invalid slot id: {}",
|
||||
left_part
|
||||
);
|
||||
let parsed_key_uri = KeyUri::YubikeyPivKey(YubikeyPivKey {
|
||||
key_name: host_or_name.to_string(),
|
||||
algorithm,
|
||||
@@ -156,7 +237,11 @@ pub fn parse_key_uri(key_uri: &str) -> XResult<KeyUri> {
|
||||
if "" != usage {
|
||||
return simple_error!("Key uri's usage must be empty.");
|
||||
}
|
||||
let algorithm = opt_value_result!(AlgorithmId::from_str(algorithm), "Invalid algorithm id: {}", algorithm);
|
||||
let algorithm = opt_value_result!(
|
||||
KeyAlgorithmId::from_str(algorithm),
|
||||
"Invalid algorithm id: {}",
|
||||
algorithm
|
||||
);
|
||||
let hmac_enc_private_key = left_part.to_string();
|
||||
let parsed_key_uri = KeyUri::YubikeyHmacEncSoftKey(YubikeyHmacEncSoftKey {
|
||||
key_name: host_or_name.to_string(),
|
||||
@@ -174,7 +259,10 @@ pub fn parse_key_uri(key_uri: &str) -> XResult<KeyUri> {
|
||||
fn test_parse_key_uri_01() {
|
||||
let se_key_uri =
|
||||
parse_key_uri("key://hatter-mac-pro:se/p256:signing:BASE64(dataRepresentation)").unwrap();
|
||||
assert_eq!("key://hatter-mac-pro:se/p256:signing:BASE64(dataRepresentation)", se_key_uri.to_string());
|
||||
assert_eq!(
|
||||
"key://hatter-mac-pro:se/p256:signing:BASE64(dataRepresentation)",
|
||||
se_key_uri.to_string()
|
||||
);
|
||||
match se_key_uri {
|
||||
KeyUri::SecureEnclaveKey(se_key_uri) => {
|
||||
assert_eq!("hatter-mac-pro", se_key_uri.host);
|
||||
@@ -192,7 +280,10 @@ fn test_parse_key_uri_02() {
|
||||
let se_key_uri =
|
||||
parse_key_uri("key://hatter-mac-m1:se/p256:key_agreement:BASE64(dataRepresentation)")
|
||||
.unwrap();
|
||||
assert_eq!("key://hatter-mac-m1:se/p256:key_agreement:BASE64(dataRepresentation)", se_key_uri.to_string());
|
||||
assert_eq!(
|
||||
"key://hatter-mac-m1:se/p256:key_agreement:BASE64(dataRepresentation)",
|
||||
se_key_uri.to_string()
|
||||
);
|
||||
match se_key_uri {
|
||||
KeyUri::SecureEnclaveKey(se_key_uri) => {
|
||||
assert_eq!("hatter-mac-m1", se_key_uri.host);
|
||||
@@ -208,11 +299,14 @@ fn test_parse_key_uri_02() {
|
||||
#[test]
|
||||
fn test_parse_key_uri_03() {
|
||||
let se_key_uri = parse_key_uri("key://yubikey-5n:piv/p256::9a").unwrap();
|
||||
assert_eq!("key://yubikey-5n:piv/p256::authentication", se_key_uri.to_string());
|
||||
assert_eq!(
|
||||
"key://yubikey-5n:piv/p256::authentication",
|
||||
se_key_uri.to_string()
|
||||
);
|
||||
match se_key_uri {
|
||||
KeyUri::YubikeyPivKey(piv_key_uri) => {
|
||||
assert_eq!("yubikey-5n", piv_key_uri.key_name);
|
||||
assert_eq!(AlgorithmId::EccP256, piv_key_uri.algorithm);
|
||||
assert_eq!(KeyAlgorithmId::EccP256, piv_key_uri.algorithm);
|
||||
assert_eq!(SlotId::Authentication, piv_key_uri.slot);
|
||||
}
|
||||
_ => {
|
||||
|
||||
@@ -1,15 +1,66 @@
|
||||
use std::collections::HashMap;
|
||||
use ecdsa::elliptic_curve::rand_core::OsRng;
|
||||
use openssl::bn::{BigNum, BigNumContext};
|
||||
use openssl::pkey::PKey;
|
||||
use openssl::rsa::{Padding, Rsa};
|
||||
use rsa::RsaPublicKey;
|
||||
use rsa::{Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey};
|
||||
use rust_util::{util_msg, XResult};
|
||||
use rust_util::util_msg::MessageType;
|
||||
use spki::DecodePublicKey;
|
||||
use rsa::pkcs1::DecodeRsaPublicKey;
|
||||
use rsa::traits::PublicKeyParts;
|
||||
use spki::EncodePublicKey;
|
||||
use rsa::pkcs1::LineEnding;
|
||||
use rsa::pkcs8::EncodePrivateKey;
|
||||
use sha2::{Sha256, Sha384, Sha512};
|
||||
use crate::digestutil;
|
||||
use crate::util::{base64_decode, base64_encode};
|
||||
|
||||
pub enum RsaSignAlgorithm {
|
||||
Rs256,
|
||||
Rs384,
|
||||
Rs512,
|
||||
}
|
||||
|
||||
impl RsaSignAlgorithm {
|
||||
pub fn from_str(alg: &str) -> Option<RsaSignAlgorithm> {
|
||||
match alg {
|
||||
"RS256" => Some(RsaSignAlgorithm::Rs256),
|
||||
"RS384" => Some(RsaSignAlgorithm::Rs384),
|
||||
"RS512" => Some(RsaSignAlgorithm::Rs512),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sign(rsa_private_key: &RsaPrivateKey, rsa_sign_algorithm: RsaSignAlgorithm, message: &[u8]) -> XResult<Vec<u8>> {
|
||||
match rsa_sign_algorithm {
|
||||
RsaSignAlgorithm::Rs256 => {
|
||||
let raw_in = digestutil::sha256_bytes(&message);
|
||||
Ok(rsa_private_key.sign(Pkcs1v15Sign::new::<Sha256>(), &raw_in)?)
|
||||
}
|
||||
RsaSignAlgorithm::Rs384 => {
|
||||
let raw_in = digestutil::sha384_bytes(&message);
|
||||
Ok(rsa_private_key.sign(Pkcs1v15Sign::new::<Sha384>(), &raw_in)?)
|
||||
}
|
||||
RsaSignAlgorithm::Rs512 => {
|
||||
let raw_in = digestutil::sha512_bytes(&message);
|
||||
Ok(rsa_private_key.sign(Pkcs1v15Sign::new::<Sha512>(), &raw_in)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_rsa_keypair(bit_size: usize) -> XResult<(String, String, String, Vec<u8>, String)> {
|
||||
let rsa_private_key = opt_result!(RsaPrivateKey::new(&mut OsRng, bit_size), "Generate RSA private key failed: {}");
|
||||
let rsa_public_key = rsa_private_key.to_public_key();
|
||||
let secret_key_der_base64 = base64_encode(rsa_private_key.to_pkcs8_der()?.as_bytes());
|
||||
let secret_key_pem = rsa_private_key.to_pkcs8_pem(LineEnding::LF)?.to_string();
|
||||
let public_key_pem = rsa_public_key.to_public_key_pem(LineEnding::LF)?;
|
||||
let public_key_der = rsa_public_key.to_public_key_der()?.to_vec();
|
||||
let jwk_ec_key = rsa_public_key_to_jwk(&rsa_public_key)?;
|
||||
Ok((secret_key_der_base64, secret_key_pem, public_key_pem, public_key_der, jwk_ec_key))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RsaCrt {
|
||||
// n = p * q
|
||||
@@ -160,7 +211,10 @@ fn pkcs1_padding_for_sign(bs: &[u8], bit_len: usize) -> XResult<Vec<u8>> {
|
||||
|
||||
pub fn convert_rsa_to_jwk(public_key: &str) -> XResult<String> {
|
||||
let rsa_public_key = try_parse_rsa(public_key)?;
|
||||
rsa_public_key_to_jwk(&rsa_public_key)
|
||||
}
|
||||
|
||||
pub fn rsa_public_key_to_jwk(rsa_public_key: &RsaPublicKey) -> XResult<String> {
|
||||
let e_bytes = rsa_public_key.e().to_bytes_be();
|
||||
let n_bytes = rsa_public_key.n().to_bytes_be();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user