use ring::signature::{self, EcdsaSigningAlgorithm, EdDSAParameters};
use std::fmt;
use std::hash::{Hash, Hasher};
use yasna::models::ObjectIdentifier;
use yasna::DERWriter;
use yasna::Tag;
use crate::oid::*;
use crate::RcgenError;
pub(crate) enum SignAlgo {
EcDsa(&'static EcdsaSigningAlgorithm),
EdDsa(&'static EdDSAParameters),
Rsa(),
}
#[derive(PartialEq, Eq)]
pub(crate) enum SignatureAlgorithmParams {
None,
Null,
RsaPss {
hash_algorithm: &'static [u64],
salt_length: u64,
},
}
pub struct SignatureAlgorithm {
oids_sign_alg: &'static [&'static [u64]],
pub(crate) sign_alg: SignAlgo,
oid_components: &'static [u64],
params: SignatureAlgorithmParams,
}
impl fmt::Debug for SignatureAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use algo::*;
if self == &PKCS_RSA_SHA256 {
write!(f, "PKCS_RSA_SHA256")
} else if self == &PKCS_RSA_SHA384 {
write!(f, "PKCS_RSA_SHA384")
} else if self == &PKCS_RSA_SHA512 {
write!(f, "PKCS_RSA_SHA512")
} else if self == &PKCS_RSA_PSS_SHA256 {
write!(f, "PKCS_RSA_PSS_SHA256")
} else if self == &PKCS_ECDSA_P256_SHA256 {
write!(f, "PKCS_ECDSA_P256_SHA256")
} else if self == &PKCS_ECDSA_P384_SHA384 {
write!(f, "PKCS_ECDSA_P384_SHA384")
} else if self == &PKCS_ED25519 {
write!(f, "PKCS_ED25519")
} else {
write!(f, "Unknown")
}
}
}
impl PartialEq for SignatureAlgorithm {
fn eq(&self, other: &Self) -> bool {
(self.oids_sign_alg, self.oid_components) == (other.oids_sign_alg, other.oid_components)
}
}
impl Eq for SignatureAlgorithm {}
impl Hash for SignatureAlgorithm {
fn hash<H: Hasher>(&self, state: &mut H) {
self.oids_sign_alg.hash(state);
}
}
impl SignatureAlgorithm {
pub(crate) fn iter() -> std::slice::Iter<'static, &'static SignatureAlgorithm> {
use algo::*;
static ALGORITHMS: &[&SignatureAlgorithm] = &[
&PKCS_RSA_SHA256,
&PKCS_RSA_SHA384,
&PKCS_RSA_SHA512,
&PKCS_ECDSA_P256_SHA256,
&PKCS_ECDSA_P384_SHA384,
&PKCS_ED25519,
];
ALGORITHMS.iter()
}
pub fn from_oid(oid: &[u64]) -> Result<&'static SignatureAlgorithm, RcgenError> {
for algo in Self::iter() {
if algo.oid_components == oid {
return Ok(algo);
}
}
Err(RcgenError::UnsupportedSignatureAlgorithm)
}
}
pub mod algo {
use super::*;
pub static PKCS_RSA_SHA256: SignatureAlgorithm = SignatureAlgorithm {
oids_sign_alg: &[&OID_RSA_ENCRYPTION],
sign_alg: SignAlgo::Rsa(),
oid_components: &[1, 2, 840, 113549, 1, 1, 11],
params: SignatureAlgorithmParams::Null,
};
pub static PKCS_RSA_SHA384: SignatureAlgorithm = SignatureAlgorithm {
oids_sign_alg: &[&OID_RSA_ENCRYPTION],
sign_alg: SignAlgo::Rsa(),
oid_components: &[1, 2, 840, 113549, 1, 1, 12],
params: SignatureAlgorithmParams::Null,
};
pub static PKCS_RSA_SHA512: SignatureAlgorithm = SignatureAlgorithm {
oids_sign_alg: &[&OID_RSA_ENCRYPTION],
sign_alg: SignAlgo::Rsa(),
oid_components: &[1, 2, 840, 113549, 1, 1, 13],
params: SignatureAlgorithmParams::Null,
};
pub(crate) static PKCS_RSA_PSS_SHA256: SignatureAlgorithm = SignatureAlgorithm {
oids_sign_alg: &[&OID_RSASSA_PSS],
sign_alg: SignAlgo::Rsa(),
oid_components: &OID_RSASSA_PSS, params: SignatureAlgorithmParams::RsaPss {
hash_algorithm: &[2, 16, 840, 1, 101, 3, 4, 2, 1],
salt_length: 20,
},
};
pub static PKCS_ECDSA_P256_SHA256: SignatureAlgorithm = SignatureAlgorithm {
oids_sign_alg: &[&OID_EC_PUBLIC_KEY, &OID_EC_SECP_256_R1],
sign_alg: SignAlgo::EcDsa(&signature::ECDSA_P256_SHA256_ASN1_SIGNING),
oid_components: &[1, 2, 840, 10045, 4, 3, 2],
params: SignatureAlgorithmParams::None,
};
pub static PKCS_ECDSA_P384_SHA384: SignatureAlgorithm = SignatureAlgorithm {
oids_sign_alg: &[&OID_EC_PUBLIC_KEY, &OID_EC_SECP_384_R1],
sign_alg: SignAlgo::EcDsa(&signature::ECDSA_P384_SHA384_ASN1_SIGNING),
oid_components: &[1, 2, 840, 10045, 4, 3, 3],
params: SignatureAlgorithmParams::None,
};
pub static PKCS_ED25519: SignatureAlgorithm = SignatureAlgorithm {
oids_sign_alg: &[&[1, 3, 101, 112]],
sign_alg: SignAlgo::EdDsa(&signature::ED25519),
oid_components: &[1, 3, 101, 112],
params: SignatureAlgorithmParams::None,
};
}
impl SignatureAlgorithm {
fn alg_ident_oid(&self) -> ObjectIdentifier {
ObjectIdentifier::from_slice(self.oid_components)
}
fn write_params(&self, writer: &mut yasna::DERWriterSeq) {
match self.params {
SignatureAlgorithmParams::None => (),
SignatureAlgorithmParams::Null => {
writer.next().write_null();
},
SignatureAlgorithmParams::RsaPss {
hash_algorithm,
salt_length,
} => {
writer.next().write_sequence(|writer| {
let oid = ObjectIdentifier::from_slice(hash_algorithm);
writer.next().write_tagged(Tag::context(0), |writer| {
writer.write_sequence(|writer| {
writer.next().write_oid(&oid);
});
});
writer.next().write_tagged(Tag::context(1), |writer| {
writer.write_sequence(|writer| {
const ID_MGF1: &[u64] = &[1, 2, 840, 113549, 1, 1, 8];
let oid = ObjectIdentifier::from_slice(ID_MGF1);
writer.next().write_oid(&oid);
writer.next().write_sequence(|writer| {
let oid = ObjectIdentifier::from_slice(hash_algorithm);
writer.next().write_oid(&oid);
writer.next().write_null();
});
});
});
writer.next().write_tagged(Tag::context(2), |writer| {
writer.write_u64(salt_length);
});
})
},
}
}
pub(crate) fn write_alg_ident(&self, writer: DERWriter) {
writer.write_sequence(|writer| {
writer.next().write_oid(&self.alg_ident_oid());
self.write_params(writer);
});
}
pub(crate) fn write_oids_sign_alg(&self, writer: DERWriter) {
writer.write_sequence(|writer| {
for oid in self.oids_sign_alg {
let oid = ObjectIdentifier::from_slice(oid);
writer.next().write_oid(&oid);
}
self.write_params(writer);
});
}
}