mod ed25519;
mod hash;
mod rsa;
pub use self::{
ed25519::{read_ed25519_verifying_key, sign_ed25519, verify_ed25519},
hash::{digest, CountingHasher, HashStatus, InsufficientInput},
rsa::{read_rsa_public_key, sign_rsa, verify_rsa},
};
use crate::util::CanonicalStr;
use ::rsa::{RsaPrivateKey, RsaPublicKey};
use ed25519_dalek::{SigningKey as Ed25519SigningKey, VerifyingKey as Ed25519VerifyingKey};
use pkcs8::{der::pem::PemLabel, Document, PrivateKeyInfo};
use std::{
error::Error,
fmt::{self, Display, Formatter},
};
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum KeyType {
Rsa,
Ed25519,
}
impl CanonicalStr for KeyType {
fn canonical_str(&self) -> &'static str {
match self {
Self::Rsa => "rsa",
Self::Ed25519 => "ed25519",
}
}
}
impl Display for KeyType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(self.canonical_str())
}
}
impl fmt::Debug for KeyType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum HashAlgorithm {
Sha256,
#[cfg(feature = "pre-rfc8301")]
Sha1,
}
impl HashAlgorithm {
pub fn all() -> Vec<Self> {
vec![
Self::Sha256,
#[cfg(feature = "pre-rfc8301")]
Self::Sha1,
]
}
}
impl CanonicalStr for HashAlgorithm {
fn canonical_str(&self) -> &'static str {
match self {
Self::Sha256 => "sha256",
#[cfg(feature = "pre-rfc8301")]
Self::Sha1 => "sha1",
}
}
}
impl Display for HashAlgorithm {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(self.canonical_str())
}
}
impl fmt::Debug for HashAlgorithm {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum DecodeSigningKeyError {
InvalidPemDocument,
NotAPrivateKeyInfoDocument,
InvalidKeyData,
UnsupportedKeyType,
}
impl Display for DecodeSigningKeyError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidPemDocument => write!(f, "invalid PEM document"),
Self::NotAPrivateKeyInfoDocument => write!(f, "not a PKCS#8 PrivateKeyInfo document"),
Self::InvalidKeyData => write!(f, "invalid private key data"),
Self::UnsupportedKeyType => write!(f, "unsupported key type"),
}
}
}
impl Error for DecodeSigningKeyError {}
#[derive(Debug)]
pub enum SigningKey {
Rsa(RsaPrivateKey),
Ed25519(Ed25519SigningKey),
}
impl SigningKey {
pub fn key_type(&self) -> KeyType {
match self {
Self::Rsa(_) => KeyType::Rsa,
Self::Ed25519(_) => KeyType::Ed25519,
}
}
pub fn signature_length(&self) -> usize {
match self {
Self::Rsa(k) => {
use ::rsa::traits::PublicKeyParts;
k.size()
}
Self::Ed25519(_) => ::ed25519_dalek::SIGNATURE_LENGTH,
}
}
pub fn from_pkcs8_pem(s: &str) -> Result<Self, DecodeSigningKeyError> {
let (label, doc) = Document::from_pem(s)
.map_err(|_| DecodeSigningKeyError::InvalidPemDocument)?;
PrivateKeyInfo::validate_pem_label(label)
.map_err(|_| DecodeSigningKeyError::NotAPrivateKeyInfoDocument)?;
let pk = PrivateKeyInfo::try_from(doc.as_bytes())
.map_err(|_| DecodeSigningKeyError::InvalidKeyData)?;
if let Ok(k) = RsaPrivateKey::try_from(pk.clone()) {
Ok(Self::Rsa(k))
} else if let Ok(k) = Ed25519SigningKey::try_from(pk.clone()) {
Ok(Self::Ed25519(k))
} else {
Err(DecodeSigningKeyError::UnsupportedKeyType)
}
}
}
impl AsRef<SigningKey> for SigningKey {
fn as_ref(&self) -> &Self {
self
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum VerifyingKey {
Rsa(RsaPublicKey),
Ed25519(Ed25519VerifyingKey),
}
impl VerifyingKey {
pub fn key_type(&self) -> KeyType {
match self {
Self::Rsa(_) => KeyType::Rsa,
Self::Ed25519(_) => KeyType::Ed25519,
}
}
pub fn key_size(&self) -> Option<usize> {
match self {
Self::Rsa(public_key) => Some(self::rsa::get_public_key_size(public_key)),
Self::Ed25519(_) => None,
}
}
pub fn validate_min_key_size(&self) -> Result<(), VerificationError> {
match (self, self.key_size()) {
(Self::Rsa(_), Some(n)) if n < self::rsa::MIN_KEY_BITS => {
return Err(VerificationError::InsufficientKeySize);
}
_ => {}
}
Ok(())
}
pub fn from_key_data(
key_type: KeyType,
key_data: &[u8],
) -> Result<Self, Box<dyn Error + Send + Sync + 'static>> {
match key_type {
KeyType::Rsa => {
let public_key = read_rsa_public_key(key_data)?;
Ok(Self::Rsa(public_key))
}
KeyType::Ed25519 => {
let verifying_key = read_ed25519_verifying_key(key_data)?;
Ok(Self::Ed25519(verifying_key))
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SigningError {
SigningFailure,
}
impl Display for SigningError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::SigningFailure => write!(f, "failed to perform signing"),
}
}
}
impl Error for SigningError {}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum VerificationError {
InvalidKey,
InsufficientKeySize,
VerificationFailure,
}
impl Display for VerificationError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidKey => write!(f, "invalid key data"),
Self::InsufficientKeySize => write!(f, "key too small"),
Self::VerificationFailure => write!(f, "signature did not verify"),
}
}
}
impl Error for VerificationError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn signing_key_from_pkcs8_pem() {
let key = SigningKey::from_pkcs8_pem("no PEM");
assert_eq!(key.unwrap_err(), DecodeSigningKeyError::InvalidPemDocument);
let key = SigningKey::from_pkcs8_pem(
"-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEALlL9HXJq+OigwEEqTS7qzyneGP55gTq55NibbL8kSI4=
-----END PUBLIC KEY-----",
);
assert_eq!(key.unwrap_err(), DecodeSigningKeyError::NotAPrivateKeyInfoDocument);
let key = SigningKey::from_pkcs8_pem(
"-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIJGNv5VBw2H6MV5s8LYuQp8AfYZFCn26mre1YAH2Qbmd
-----END PRIVATE KEY-----",
)
.unwrap();
assert_eq!(key.key_type(), KeyType::Ed25519);
}
}