use std::{fmt, sync::Arc};
#[cfg(feature = "crypto-ring")]
use ring as backend;
#[cfg(all(feature = "crypto-aws-lc-rs", not(feature = "crypto-ring")))]
use aws_lc_rs as backend;
use backend::{
aead, hmac, rand, rsa, signature,
signature::{KeyPair, RsaParameters},
};
use zeroize::Zeroizing;
use crate::{iana, Encryptor, Error, Key, Label, Macer, Signer, Verifier};
#[derive(Clone)]
pub struct RingMacer {
alg: i64,
kid: Option<Vec<u8>>,
key: Arc<hmac::Key>,
raw_key: Arc<Zeroizing<Vec<u8>>>,
tag_len: usize,
key_ops: Option<Vec<Label>>,
}
impl fmt::Debug for RingMacer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RingMacer")
.field("alg", &self.alg)
.field("kid", &self.kid)
.field("tag_len", &self.tag_len)
.finish_non_exhaustive()
}
}
impl RingMacer {
pub fn new(alg: i64, key: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
let (algorithm, tag_len) = hmac_algorithm(alg)?;
Ok(Self {
alg,
kid,
key: Arc::new(hmac::Key::new(algorithm, key)),
raw_key: Arc::new(Zeroizing::new(key.to_vec())),
tag_len,
key_ops: None,
})
}
pub fn from_cose_key(key: &Key) -> Result<Self, Error> {
key.require_integer_kty(iana::KeyTypeSymmetric)?;
let alg = key.required_integer_alg("crypto backend")?;
let mut macer = Self::new(
alg,
key.required_bytes(iana::SymmetricKeyParameterK, "k")?,
key.kid_owned()?,
)?;
macer.key_ops = key.ops()?;
if !crate::util::key_ops_allow(
&macer.key_ops,
&[iana::KeyOperationMacCreate, iana::KeyOperationMacVerify],
) {
return Err(Error::custom(
"COSE_Key key_ops permits neither MAC create nor MAC verify",
));
}
Ok(macer)
}
pub fn to_cose_key(&self) -> Result<Key, Error> {
Ok(symmetric_cose_key(
self.alg,
self.raw_key.as_slice(),
self.kid.as_deref(),
None,
&self.key_ops,
))
}
pub fn algorithm(&self) -> i64 {
self.alg
}
}
impl Macer for RingMacer {
fn alg(&self) -> Option<Label> {
Some(self.alg.into())
}
fn kid(&self) -> Option<&[u8]> {
self.kid.as_deref()
}
fn mac_create(&self, data: &[u8]) -> Result<Vec<u8>, Error> {
crate::util::require_key_ops(&self.key_ops, &[iana::KeyOperationMacCreate], "MAC create")?;
let tag = hmac::sign(self.key.as_ref(), data);
Ok(tag.as_ref()[..self.tag_len].to_vec())
}
fn mac_verify(&self, data: &[u8], tag: &[u8]) -> Result<(), Error> {
crate::util::require_key_ops(&self.key_ops, &[iana::KeyOperationMacVerify], "MAC verify")?;
if tag.len() != self.tag_len {
return Err(Error::verify("HMAC tag length mismatch"));
}
let expected = hmac::sign(self.key.as_ref(), data);
if constant_time_eq(&expected.as_ref()[..self.tag_len], tag) {
Ok(())
} else {
Err(Error::verify("HMAC tag mismatch"))
}
}
}
#[derive(Clone)]
pub struct RingEncryptor {
alg: i64,
kid: Option<Vec<u8>>,
key: Arc<aead::LessSafeKey>,
raw_key: Arc<Zeroizing<Vec<u8>>>,
base_iv: Option<Vec<u8>>,
key_ops: Option<Vec<Label>>,
}
impl fmt::Debug for RingEncryptor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RingEncryptor")
.field("alg", &self.alg)
.field("kid", &self.kid)
.field("base_iv", &self.base_iv)
.finish_non_exhaustive()
}
}
impl RingEncryptor {
pub fn new(alg: i64, key: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
let algorithm = aead_algorithm(alg)?;
let unbound = aead::UnboundKey::new(algorithm, key)
.map_err(|_| Error::custom("invalid AEAD key length"))?;
Ok(Self {
alg,
kid,
key: Arc::new(aead::LessSafeKey::new(unbound)),
raw_key: Arc::new(Zeroizing::new(key.to_vec())),
base_iv: None,
key_ops: None,
})
}
pub fn from_cose_key(key: &Key) -> Result<Self, Error> {
key.require_integer_kty(iana::KeyTypeSymmetric)?;
let alg = key.required_integer_alg("crypto backend")?;
let mut encryptor = Self::new(
alg,
key.required_bytes(iana::SymmetricKeyParameterK, "k")?,
key.kid_owned()?,
)?;
encryptor.base_iv = key.base_iv()?.map(ToOwned::to_owned);
encryptor.key_ops = key.ops()?;
if !crate::util::key_ops_allow(
&encryptor.key_ops,
&[iana::KeyOperationEncrypt, iana::KeyOperationDecrypt],
) {
return Err(Error::custom(
"COSE_Key key_ops permits neither encryption nor decryption",
));
}
Ok(encryptor)
}
pub fn with_base_iv(mut self, base_iv: impl Into<Vec<u8>>) -> Self {
self.base_iv = Some(base_iv.into());
self
}
pub fn to_cose_key(&self) -> Result<Key, Error> {
Ok(symmetric_cose_key(
self.alg,
self.raw_key.as_slice(),
self.kid.as_deref(),
self.base_iv.as_deref(),
&self.key_ops,
))
}
pub fn algorithm(&self) -> i64 {
self.alg
}
}
impl Encryptor for RingEncryptor {
fn alg(&self) -> Option<Label> {
Some(self.alg.into())
}
fn kid(&self) -> Option<&[u8]> {
self.kid.as_deref()
}
fn nonce_size(&self) -> usize {
aead::NONCE_LEN
}
fn base_iv(&self) -> Option<&[u8]> {
self.base_iv.as_deref()
}
fn encrypt(&self, nonce: &[u8], plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>, Error> {
crate::util::require_key_ops(&self.key_ops, &[iana::KeyOperationEncrypt], "encryption")?;
let nonce = aead::Nonce::try_assume_unique_for_key(nonce)
.map_err(|_| Error::custom("invalid AEAD nonce length"))?;
let mut out = plaintext.to_vec();
self.key
.seal_in_place_append_tag(nonce, aead::Aad::from(aad), &mut out)
.map_err(|_| Error::custom("AEAD encryption failed"))?;
Ok(out)
}
fn decrypt(&self, nonce: &[u8], ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>, Error> {
crate::util::require_key_ops(&self.key_ops, &[iana::KeyOperationDecrypt], "decryption")?;
let nonce = aead::Nonce::try_assume_unique_for_key(nonce)
.map_err(|_| Error::custom("invalid AEAD nonce length"))?;
let mut in_out = ciphertext.to_vec();
let plaintext_len = self
.key
.open_in_place(nonce, aead::Aad::from(aad), &mut in_out)
.map_err(|_| Error::verify("AEAD authentication failed"))?
.len();
in_out.truncate(plaintext_len);
Ok(in_out)
}
}
#[derive(Debug)]
pub struct RingSigner {
alg: i64,
kid: Option<Vec<u8>>,
key: RingSigningKey,
}
enum RingSigningKey {
Ed25519(signature::Ed25519KeyPair),
Ecdsa(signature::EcdsaKeyPair),
Rsa {
key_pair: rsa::KeyPair,
padding: &'static dyn signature::RsaEncoding,
},
}
impl fmt::Debug for RingSigningKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RingSigningKey::Ed25519(_) => f.write_str("Ed25519"),
RingSigningKey::Ecdsa(_) => f.write_str("Ecdsa"),
RingSigningKey::Rsa { .. } => f.write_str("Rsa"),
}
}
}
impl RingSigner {
pub fn from_cose_key(key: &Key) -> Result<Self, Error> {
key.require_any_operation(&[iana::KeyOperationSign], "signing")?;
let alg = key.required_integer_alg("crypto backend")?;
match alg {
iana::AlgorithmEdDSA | iana::AlgorithmEd25519 => Self::ed25519_from_cose_key(key, alg),
iana::AlgorithmES256
| iana::AlgorithmESP256
| iana::AlgorithmES384
| iana::AlgorithmESP384 => Self::ecdsa_from_cose_key(key, alg),
iana::AlgorithmRS256
| iana::AlgorithmRS384
| iana::AlgorithmRS512
| iana::AlgorithmPS256
| iana::AlgorithmPS384
| iana::AlgorithmPS512 => Self::rsa_from_cose_key(key, alg),
_ => Err(unsupported_alg("signing", alg)),
}
}
pub fn ed25519_from_pkcs8(pkcs8: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
Self::ed25519_from_pkcs8_with_alg(iana::AlgorithmEd25519, pkcs8, kid)
}
pub fn ed25519_from_pkcs8_with_alg(
alg: i64,
pkcs8: &[u8],
kid: Option<Vec<u8>>,
) -> Result<Self, Error> {
require_ed25519_alg(alg)?;
let key = signature::Ed25519KeyPair::from_pkcs8(pkcs8)
.map_err(|_| Error::custom("invalid Ed25519 PKCS#8 key"))?;
Ok(Self {
alg,
kid,
key: RingSigningKey::Ed25519(key),
})
}
pub fn ed25519_from_seed_and_public_key(
seed: &[u8],
public_key: &[u8],
kid: Option<Vec<u8>>,
) -> Result<Self, Error> {
Self::ed25519_from_seed_and_public_key_with_alg(
iana::AlgorithmEd25519,
seed,
public_key,
kid,
)
}
pub fn ed25519_from_seed_and_public_key_with_alg(
alg: i64,
seed: &[u8],
public_key: &[u8],
kid: Option<Vec<u8>>,
) -> Result<Self, Error> {
require_ed25519_alg(alg)?;
let key = signature::Ed25519KeyPair::from_seed_and_public_key(seed, public_key)
.map_err(|_| Error::custom("invalid Ed25519 key material"))?;
Ok(Self {
alg,
kid,
key: RingSigningKey::Ed25519(key),
})
}
pub fn es256_from_pkcs8(pkcs8: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
Self::ecdsa_from_pkcs8(
iana::AlgorithmES256,
&signature::ECDSA_P256_SHA256_FIXED_SIGNING,
pkcs8,
kid,
)
}
pub fn esp256_from_pkcs8(pkcs8: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
Self::ecdsa_from_pkcs8(
iana::AlgorithmESP256,
&signature::ECDSA_P256_SHA256_FIXED_SIGNING,
pkcs8,
kid,
)
}
pub fn es384_from_pkcs8(pkcs8: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
Self::ecdsa_from_pkcs8(
iana::AlgorithmES384,
&signature::ECDSA_P384_SHA384_FIXED_SIGNING,
pkcs8,
kid,
)
}
pub fn esp384_from_pkcs8(pkcs8: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
Self::ecdsa_from_pkcs8(
iana::AlgorithmESP384,
&signature::ECDSA_P384_SHA384_FIXED_SIGNING,
pkcs8,
kid,
)
}
pub fn rsa_from_pkcs8(alg: i64, pkcs8: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
let padding = rsa_signing_algorithm(alg)?;
let key_pair =
rsa::KeyPair::from_pkcs8(pkcs8).map_err(|_| Error::custom("invalid RSA PKCS#8 key"))?;
Ok(Self {
alg,
kid,
key: RingSigningKey::Rsa { key_pair, padding },
})
}
pub fn rsa_from_der(alg: i64, der: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
let padding = rsa_signing_algorithm(alg)?;
let key_pair =
rsa::KeyPair::from_der(der).map_err(|_| Error::custom("invalid RSA DER key"))?;
Ok(Self {
alg,
kid,
key: RingSigningKey::Rsa { key_pair, padding },
})
}
pub fn public_key(&self) -> Option<&[u8]> {
match &self.key {
RingSigningKey::Ed25519(key) => Some(key.public_key().as_ref()),
RingSigningKey::Ecdsa(key) => Some(key.public_key().as_ref()),
RingSigningKey::Rsa { .. } => None,
}
}
pub fn to_cose_key(&self) -> Result<Key, Error> {
let mut key = match &self.key {
RingSigningKey::Ed25519(key) => Ok(okp_public_cose_key(
self.alg,
key.public_key().as_ref(),
self.kid.as_deref(),
)),
RingSigningKey::Ecdsa(key) => {
ec2_public_cose_key(self.alg, key.public_key().as_ref(), self.kid.as_deref())
}
RingSigningKey::Rsa { .. } => Err(Error::custom(
"cannot export a COSE_Key from an RSA RingSigner: the backend exposes no public key",
)),
}?;
key.set_ops([iana::KeyOperationVerify]);
Ok(key)
}
pub fn algorithm(&self) -> i64 {
self.alg
}
fn ed25519_from_cose_key(key: &Key, alg: i64) -> Result<Self, Error> {
key.require_integer_kty(iana::KeyTypeOKP)?;
key.require_integer_parameter(
iana::OKPKeyParameterCrv,
iana::EllipticCurveEd25519,
"curve",
)?;
Self::ed25519_from_seed_and_public_key_with_alg(
alg,
key.required_bytes(iana::OKPKeyParameterD, "d")?,
key.required_bytes(iana::OKPKeyParameterX, "x")?,
key.kid_owned()?,
)
}
fn ecdsa_from_cose_key(key: &Key, alg: i64) -> Result<Self, Error> {
key.require_integer_kty(iana::KeyTypeEC2)?;
let (curve, signing_algorithm, coordinate_len) = match alg {
iana::AlgorithmES256 | iana::AlgorithmESP256 => (
iana::EllipticCurveP_256,
&signature::ECDSA_P256_SHA256_FIXED_SIGNING,
32,
),
iana::AlgorithmES384 | iana::AlgorithmESP384 => (
iana::EllipticCurveP_384,
&signature::ECDSA_P384_SHA384_FIXED_SIGNING,
48,
),
_ => return Err(unsupported_alg("ECDSA signing", alg)),
};
key.require_integer_parameter(iana::EC2KeyParameterCrv, curve, "curve")?;
let kid = key.kid_owned()?;
let public_key = ec2_uncompressed_public_key(key, coordinate_len)?;
let d = key.required_bytes(iana::EC2KeyParameterD, "d")?;
#[cfg(feature = "crypto-ring")]
let signing_key = signature::EcdsaKeyPair::from_private_key_and_public_key(
signing_algorithm,
d,
&public_key,
&rand::SystemRandom::new(),
)
.map_err(|_| Error::custom("invalid ECDSA key material"))?;
#[cfg(all(feature = "crypto-aws-lc-rs", not(feature = "crypto-ring")))]
let signing_key = signature::EcdsaKeyPair::from_private_key_and_public_key(
signing_algorithm,
d,
&public_key,
)
.map_err(|_| Error::custom("invalid ECDSA key material"))?;
Ok(Self {
alg,
kid,
key: RingSigningKey::Ecdsa(signing_key),
})
}
fn ecdsa_from_pkcs8(
alg: i64,
signing_algorithm: &'static signature::EcdsaSigningAlgorithm,
pkcs8: &[u8],
kid: Option<Vec<u8>>,
) -> Result<Self, Error> {
#[cfg(feature = "crypto-ring")]
let key = signature::EcdsaKeyPair::from_pkcs8(
signing_algorithm,
pkcs8,
&rand::SystemRandom::new(),
)
.map_err(|_| Error::custom("invalid ECDSA PKCS#8 key"))?;
#[cfg(all(feature = "crypto-aws-lc-rs", not(feature = "crypto-ring")))]
let key = signature::EcdsaKeyPair::from_pkcs8(signing_algorithm, pkcs8)
.map_err(|_| Error::custom("invalid ECDSA PKCS#8 key"))?;
Ok(Self {
alg,
kid,
key: RingSigningKey::Ecdsa(key),
})
}
fn rsa_from_cose_key(key: &Key, alg: i64) -> Result<Self, Error> {
key.require_integer_kty(iana::KeyTypeRSA)?;
let padding = rsa_signing_algorithm(alg)?;
let der = Zeroizing::new(rsa_pkcs1_private_key_der(key)?);
let key_pair = rsa::KeyPair::from_der(der.as_slice())
.map_err(|_| Error::custom("invalid RSA key material"))?;
Ok(Self {
alg,
kid: key.kid_owned()?,
key: RingSigningKey::Rsa { key_pair, padding },
})
}
}
impl Signer for RingSigner {
fn alg(&self) -> Option<Label> {
Some(self.alg.into())
}
fn kid(&self) -> Option<&[u8]> {
self.kid.as_deref()
}
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, Error> {
match &self.key {
RingSigningKey::Ed25519(key) => Ok(key.sign(data).as_ref().to_vec()),
RingSigningKey::Ecdsa(key) => {
let rng = rand::SystemRandom::new();
Ok(key
.sign(&rng, data)
.map_err(|_| Error::custom("ECDSA signing failed"))?
.as_ref()
.to_vec())
}
RingSigningKey::Rsa { key_pair, padding } => {
let rng = rand::SystemRandom::new();
#[cfg(feature = "crypto-ring")]
let sig_len = key_pair.public().modulus_len();
#[cfg(all(feature = "crypto-aws-lc-rs", not(feature = "crypto-ring")))]
let sig_len = key_pair.public_modulus_len();
let mut signature = vec![0; sig_len];
key_pair
.sign(*padding, &rng, data, &mut signature)
.map_err(|_| Error::custom("RSA signing failed"))?;
Ok(signature)
}
}
}
}
#[derive(Clone, Debug)]
pub struct RingVerifier {
alg: i64,
kid: Option<Vec<u8>>,
key: RingVerificationKey,
}
#[derive(Clone, Debug)]
enum RingVerificationKey {
Ed25519(Vec<u8>),
Ecdsa(Vec<u8>),
RsaComponents { n: Vec<u8>, e: Vec<u8> },
RsaDer(Vec<u8>),
}
impl RingVerifier {
pub fn from_cose_key(key: &Key) -> Result<Self, Error> {
key.require_any_operation(&[iana::KeyOperationVerify], "signature verification")?;
let alg = key.required_integer_alg("crypto backend")?;
match alg {
iana::AlgorithmEdDSA | iana::AlgorithmEd25519 => {
key.require_integer_kty(iana::KeyTypeOKP)?;
key.require_integer_parameter(
iana::OKPKeyParameterCrv,
iana::EllipticCurveEd25519,
"curve",
)?;
Self::ed25519_with_alg(
alg,
key.required_bytes(iana::OKPKeyParameterX, "x")?,
key.kid_owned()?,
)
}
iana::AlgorithmES256
| iana::AlgorithmESP256
| iana::AlgorithmES384
| iana::AlgorithmESP384 => {
key.require_integer_kty(iana::KeyTypeEC2)?;
let (expected_curve, coordinate_len) =
if matches!(alg, iana::AlgorithmES256 | iana::AlgorithmESP256) {
(iana::EllipticCurveP_256, 32)
} else {
(iana::EllipticCurveP_384, 48)
};
key.require_integer_parameter(iana::EC2KeyParameterCrv, expected_curve, "curve")?;
Self::ecdsa(
alg,
&ec2_uncompressed_public_key(key, coordinate_len)?,
key.kid_owned()?,
)
}
iana::AlgorithmRS256
| iana::AlgorithmRS384
| iana::AlgorithmRS512
| iana::AlgorithmPS256
| iana::AlgorithmPS384
| iana::AlgorithmPS512 => {
key.require_integer_kty(iana::KeyTypeRSA)?;
Self::rsa_components(
alg,
key.required_bytes(iana::RSAKeyParameterN, "n")?,
key.required_bytes(iana::RSAKeyParameterE, "e")?,
key.kid_owned()?,
)
}
_ => Err(unsupported_alg("verification", alg)),
}
}
pub fn ed25519(public_key: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
Self::ed25519_with_alg(iana::AlgorithmEd25519, public_key, kid)
}
pub fn ed25519_with_alg(
alg: i64,
public_key: &[u8],
kid: Option<Vec<u8>>,
) -> Result<Self, Error> {
require_ed25519_alg(alg)?;
Ok(Self {
alg,
kid,
key: RingVerificationKey::Ed25519(public_key.to_vec()),
})
}
pub fn ecdsa(alg: i64, public_key: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
ecdsa_verification_algorithm(alg)?;
Ok(Self {
alg,
kid,
key: RingVerificationKey::Ecdsa(public_key.to_vec()),
})
}
pub fn rsa_components(
alg: i64,
n: &[u8],
e: &[u8],
kid: Option<Vec<u8>>,
) -> Result<Self, Error> {
rsa_verification_algorithm(alg)?;
Ok(Self {
alg,
kid,
key: RingVerificationKey::RsaComponents {
n: n.to_vec(),
e: e.to_vec(),
},
})
}
pub fn rsa_der(alg: i64, der: &[u8], kid: Option<Vec<u8>>) -> Result<Self, Error> {
rsa_verification_algorithm(alg)?;
Ok(Self {
alg,
kid,
key: RingVerificationKey::RsaDer(der.to_vec()),
})
}
pub fn to_cose_key(&self) -> Result<Key, Error> {
let mut key = match &self.key {
RingVerificationKey::Ed25519(public_key) => Ok(okp_public_cose_key(
self.alg,
public_key,
self.kid.as_deref(),
)),
RingVerificationKey::Ecdsa(public_key) => {
ec2_public_cose_key(self.alg, public_key, self.kid.as_deref())
}
RingVerificationKey::RsaComponents { n, e } => {
Ok(rsa_public_cose_key(self.alg, n, e, self.kid.as_deref()))
}
RingVerificationKey::RsaDer(der) => {
let (n, e) = rsa_public_key_from_der(der)?;
Ok(rsa_public_cose_key(self.alg, &n, &e, self.kid.as_deref()))
}
}?;
key.set_ops([iana::KeyOperationVerify]);
Ok(key)
}
pub fn algorithm(&self) -> i64 {
self.alg
}
}
impl Verifier for RingVerifier {
fn alg(&self) -> Option<Label> {
Some(self.alg.into())
}
fn kid(&self) -> Option<&[u8]> {
self.kid.as_deref()
}
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<(), Error> {
match &self.key {
RingVerificationKey::Ed25519(public_key) => {
signature::UnparsedPublicKey::new(&signature::ED25519, public_key)
.verify(data, signature)
.map_err(|_| Error::verify("Ed25519 signature mismatch"))
}
RingVerificationKey::Ecdsa(public_key) => {
let algorithm = ecdsa_verification_algorithm(self.alg)?;
signature::UnparsedPublicKey::new(algorithm, public_key)
.verify(data, signature)
.map_err(|_| Error::verify("ECDSA signature mismatch"))
}
RingVerificationKey::RsaComponents { n, e } => {
let algorithm = rsa_verification_algorithm(self.alg)?;
let public_key = signature::RsaPublicKeyComponents { n, e };
public_key
.verify(algorithm, data, signature)
.map_err(|_| Error::verify("RSA signature mismatch"))
}
RingVerificationKey::RsaDer(der) => {
let algorithm = rsa_verification_algorithm(self.alg)?;
signature::UnparsedPublicKey::new(algorithm, der)
.verify(data, signature)
.map_err(|_| Error::verify("RSA signature mismatch"))
}
}
}
}
fn hmac_algorithm(alg: i64) -> Result<(hmac::Algorithm, usize), Error> {
match alg {
iana::AlgorithmHMAC_256_64 => Ok((hmac::HMAC_SHA256, 8)),
iana::AlgorithmHMAC_256_256 => Ok((hmac::HMAC_SHA256, 32)),
iana::AlgorithmHMAC_384_384 => Ok((hmac::HMAC_SHA384, 48)),
iana::AlgorithmHMAC_512_512 => Ok((hmac::HMAC_SHA512, 64)),
_ => Err(unsupported_alg("HMAC", alg)),
}
}
fn aead_algorithm(alg: i64) -> Result<&'static aead::Algorithm, Error> {
match alg {
iana::AlgorithmA128GCM => Ok(&aead::AES_128_GCM),
iana::AlgorithmA256GCM => Ok(&aead::AES_256_GCM),
iana::AlgorithmChaCha20Poly1305 => Ok(&aead::CHACHA20_POLY1305),
_ => Err(unsupported_alg("AEAD", alg)),
}
}
fn ecdsa_verification_algorithm(
alg: i64,
) -> Result<&'static dyn signature::VerificationAlgorithm, Error> {
match alg {
iana::AlgorithmES256 | iana::AlgorithmESP256 => Ok(&signature::ECDSA_P256_SHA256_FIXED),
iana::AlgorithmES384 | iana::AlgorithmESP384 => Ok(&signature::ECDSA_P384_SHA384_FIXED),
_ => Err(unsupported_alg("ECDSA verification", alg)),
}
}
fn rsa_signing_algorithm(alg: i64) -> Result<&'static dyn signature::RsaEncoding, Error> {
match alg {
iana::AlgorithmRS256 => Ok(&signature::RSA_PKCS1_SHA256),
iana::AlgorithmRS384 => Ok(&signature::RSA_PKCS1_SHA384),
iana::AlgorithmRS512 => Ok(&signature::RSA_PKCS1_SHA512),
iana::AlgorithmPS256 => Ok(&signature::RSA_PSS_SHA256),
iana::AlgorithmPS384 => Ok(&signature::RSA_PSS_SHA384),
iana::AlgorithmPS512 => Ok(&signature::RSA_PSS_SHA512),
_ => Err(unsupported_alg("RSA signing", alg)),
}
}
fn rsa_verification_algorithm(alg: i64) -> Result<&'static RsaParameters, Error> {
match alg {
iana::AlgorithmRS256 => Ok(&signature::RSA_PKCS1_2048_8192_SHA256),
iana::AlgorithmRS384 => Ok(&signature::RSA_PKCS1_2048_8192_SHA384),
iana::AlgorithmRS512 => Ok(&signature::RSA_PKCS1_2048_8192_SHA512),
iana::AlgorithmPS256 => Ok(&signature::RSA_PSS_2048_8192_SHA256),
iana::AlgorithmPS384 => Ok(&signature::RSA_PSS_2048_8192_SHA384),
iana::AlgorithmPS512 => Ok(&signature::RSA_PSS_2048_8192_SHA512),
_ => Err(unsupported_alg("RSA verification", alg)),
}
}
fn require_ed25519_alg(alg: i64) -> Result<(), Error> {
if matches!(alg, iana::AlgorithmEd25519 | iana::AlgorithmEdDSA) {
Ok(())
} else {
Err(unsupported_alg("Ed25519", alg))
}
}
fn ec2_uncompressed_public_key(key: &Key, coordinate_len: usize) -> Result<Vec<u8>, Error> {
let x = key.required_bytes(iana::EC2KeyParameterX, "x")?;
let y = key.required_bytes(iana::EC2KeyParameterY, "y")?;
if x.len() != coordinate_len || y.len() != coordinate_len {
return Err(Error::custom(format!(
"EC2 coordinates must be {coordinate_len} bytes, got x = {} and y = {}",
x.len(),
y.len()
)));
}
let mut out = Vec::with_capacity(1 + x.len() + y.len());
out.push(0x04);
out.extend_from_slice(x);
out.extend_from_slice(y);
Ok(out)
}
fn symmetric_cose_key(
alg: i64,
k: &[u8],
kid: Option<&[u8]>,
base_iv: Option<&[u8]>,
key_ops: &Option<Vec<Label>>,
) -> Key {
let mut key = Key::new();
key.set_kty(iana::KeyTypeSymmetric).set_alg(alg);
if let Some(kid) = kid {
key.set_kid(kid.to_vec());
}
key.insert(iana::SymmetricKeyParameterK, k.to_vec());
if let Some(base_iv) = base_iv {
key.insert(iana::KeyParameterBaseIV, base_iv.to_vec());
}
crate::util::set_key_ops(&mut key, key_ops);
key
}
fn okp_public_cose_key(alg: i64, x: &[u8], kid: Option<&[u8]>) -> Key {
let mut key = Key::new();
key.set_kty(iana::KeyTypeOKP).set_alg(alg);
if let Some(kid) = kid {
key.set_kid(kid.to_vec());
}
key.insert(iana::OKPKeyParameterCrv, iana::EllipticCurveEd25519);
key.insert(iana::OKPKeyParameterX, x.to_vec());
key
}
fn ec2_public_cose_key(alg: i64, point: &[u8], kid: Option<&[u8]>) -> Result<Key, Error> {
let (curve, coord_len) = match alg {
iana::AlgorithmES256 | iana::AlgorithmESP256 => (iana::EllipticCurveP_256, 32),
iana::AlgorithmES384 | iana::AlgorithmESP384 => (iana::EllipticCurveP_384, 48),
_ => return Err(unsupported_alg("ECDSA", alg)),
};
if point.first() != Some(&0x04) || point.len() != 1 + 2 * coord_len {
return Err(Error::custom("invalid uncompressed EC public key"));
}
let mut key = Key::new();
key.set_kty(iana::KeyTypeEC2).set_alg(alg);
if let Some(kid) = kid {
key.set_kid(kid.to_vec());
}
key.insert(iana::EC2KeyParameterCrv, curve);
key.insert(iana::EC2KeyParameterX, point[1..1 + coord_len].to_vec());
key.insert(iana::EC2KeyParameterY, point[1 + coord_len..].to_vec());
Ok(key)
}
fn rsa_public_cose_key(alg: i64, n: &[u8], e: &[u8], kid: Option<&[u8]>) -> Key {
let mut key = Key::new();
key.set_kty(iana::KeyTypeRSA).set_alg(alg);
if let Some(kid) = kid {
key.set_kid(kid.to_vec());
}
key.insert(iana::RSAKeyParameterN, n.to_vec());
key.insert(iana::RSAKeyParameterE, e.to_vec());
key
}
fn rsa_pkcs1_private_key_der(key: &Key) -> Result<Vec<u8>, Error> {
let fields = [
key.required_bytes(iana::RSAKeyParameterN, "n")?,
key.required_bytes(iana::RSAKeyParameterE, "e")?,
key.required_bytes(iana::RSAKeyParameterD, "d")?,
key.required_bytes(iana::RSAKeyParameterP, "p")?,
key.required_bytes(iana::RSAKeyParameterQ, "q")?,
key.required_bytes(iana::RSAKeyParameterDP, "dP")?,
key.required_bytes(iana::RSAKeyParameterDQ, "dQ")?,
key.required_bytes(iana::RSAKeyParameterQInv, "qInv")?,
];
let mut body = Zeroizing::new(Vec::new());
der_unsigned_integer(&[0], &mut body); for field in fields {
der_unsigned_integer(field, &mut body);
}
let mut der = Vec::with_capacity(body.len() + 4);
der.push(0x30); der_length(body.len(), &mut der);
der.extend_from_slice(body.as_slice());
Ok(der)
}
fn der_unsigned_integer(value: &[u8], out: &mut Vec<u8>) {
let mut magnitude = value;
while magnitude.len() > 1 && magnitude[0] == 0 {
magnitude = &magnitude[1..];
}
out.push(0x02); if magnitude.first().is_some_and(|&b| b & 0x80 != 0) {
der_length(magnitude.len() + 1, out);
out.push(0x00);
} else {
der_length(magnitude.len(), out);
}
out.extend_from_slice(magnitude);
}
fn der_length(len: usize, out: &mut Vec<u8>) {
if len < 0x80 {
out.push(len as u8);
return;
}
let be = len.to_be_bytes();
let first = be.iter().position(|&b| b != 0).unwrap_or(be.len() - 1);
let bytes = &be[first..];
out.push(0x80 | bytes.len() as u8);
out.extend_from_slice(bytes);
}
fn rsa_public_key_from_der(der: &[u8]) -> Result<(Vec<u8>, Vec<u8>), Error> {
let invalid = || Error::custom("invalid RSA public key DER");
let (seq, trailing) = der_take_tlv(der, 0x30).ok_or_else(invalid)?;
if !trailing.is_empty() {
return Err(invalid());
}
let (n, rest) = der_take_tlv(seq, 0x02).ok_or_else(invalid)?;
let (e, rest) = der_take_tlv(rest, 0x02).ok_or_else(invalid)?;
if !rest.is_empty() {
return Err(invalid());
}
Ok((
der_integer_magnitude(n).to_vec(),
der_integer_magnitude(e).to_vec(),
))
}
fn der_take_tlv(input: &[u8], tag: u8) -> Option<(&[u8], &[u8])> {
let (&first, rest) = input.split_first()?;
if first != tag {
return None;
}
let (len, rest) = der_read_length(rest)?;
if rest.len() < len {
return None;
}
Some(rest.split_at(len))
}
fn der_read_length(input: &[u8]) -> Option<(usize, &[u8])> {
let (&first, rest) = input.split_first()?;
if first < 0x80 {
return Some((first as usize, rest));
}
let count = (first & 0x7f) as usize;
if count == 0 || count > std::mem::size_of::<usize>() || rest.len() < count {
return None;
}
let (bytes, rest) = rest.split_at(count);
let mut len = 0usize;
for &b in bytes {
len = (len << 8) | b as usize;
}
Some((len, rest))
}
fn der_integer_magnitude(bytes: &[u8]) -> &[u8] {
match bytes.split_first() {
Some((&0x00, rest)) if !rest.is_empty() => rest,
_ => bytes,
}
}
fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
let mut diff = 0u8;
for (x, y) in a.iter().zip(b) {
diff |= x ^ y;
}
diff == 0
}
fn unsupported_alg(operation: &str, alg: i64) -> Error {
Error::custom(format!(
"unsupported {operation} algorithm {} for the built-in crypto backend",
Label::from(alg)
))
}
pub type BackendSigner = RingSigner;
pub type BackendVerifier = RingVerifier;
pub type BackendMacer = RingMacer;
pub type BackendEncryptor = RingEncryptor;
#[cfg(test)]
mod tests {
use super::{
der_length, der_unsigned_integer, ec2_public_cose_key, rsa_pkcs1_private_key_der,
rsa_public_key_from_der,
};
use crate::{iana, Key};
#[test]
fn der_length_uses_minimal_definite_form() {
let cases: &[(usize, &[u8])] = &[
(0, &[0x00]),
(5, &[0x05]),
(127, &[0x7f]),
(128, &[0x81, 0x80]),
(200, &[0x81, 0xc8]),
(257, &[0x82, 0x01, 0x01]),
];
for (len, expected) in cases {
let mut out = Vec::new();
der_length(*len, &mut out);
assert_eq!(out, *expected, "length {len}");
}
}
#[test]
fn der_unsigned_integer_is_minimal_and_positive() {
let cases: &[(&[u8], &[u8])] = &[
(&[0x00], &[0x02, 0x01, 0x00]),
(&[0x7f], &[0x02, 0x01, 0x7f]),
(&[0x80], &[0x02, 0x02, 0x00, 0x80]),
(&[0x00, 0x00, 0x01], &[0x02, 0x01, 0x01]),
(&[0x00, 0xb6], &[0x02, 0x02, 0x00, 0xb6]),
];
for (value, expected) in cases {
let mut out = Vec::new();
der_unsigned_integer(value, &mut out);
assert_eq!(out, *expected, "value {value:02x?}");
}
}
#[test]
fn rsa_pkcs1_der_wraps_components_in_a_sequence() {
let mut key = Key::new();
key.set_kty(iana::KeyTypeRSA);
for label in [
iana::RSAKeyParameterN,
iana::RSAKeyParameterE,
iana::RSAKeyParameterD,
iana::RSAKeyParameterP,
iana::RSAKeyParameterQ,
iana::RSAKeyParameterDP,
iana::RSAKeyParameterDQ,
iana::RSAKeyParameterQInv,
] {
key.insert(label, vec![0x01u8]);
}
let der = rsa_pkcs1_private_key_der(&key).unwrap();
let mut expected = vec![0x30, 0x1b, 0x02, 0x01, 0x00];
for _ in 0..8 {
expected.extend_from_slice(&[0x02, 0x01, 0x01]);
}
assert_eq!(der, expected);
let mut incomplete = Key::new();
incomplete.set_kty(iana::KeyTypeRSA);
incomplete.insert(iana::RSAKeyParameterN, vec![0x01u8]);
assert!(rsa_pkcs1_private_key_der(&incomplete).is_err());
}
#[test]
fn rsa_public_key_from_der_extracts_minimal_magnitudes() {
let der = &[
0x30, 0x09, 0x02, 0x02, 0x00, 0xb6, 0x02, 0x03, 0x01, 0x00, 0x01, ];
let (n, e) = rsa_public_key_from_der(der).unwrap();
assert_eq!(n, vec![0xb6]);
assert_eq!(e, vec![0x01, 0x00, 0x01]);
let mut trailing = der.to_vec();
trailing.push(0x00);
assert!(rsa_public_key_from_der(&trailing).is_err());
assert!(rsa_public_key_from_der(&[0x31, 0x00]).is_err());
assert!(rsa_public_key_from_der(&[0x30, 0x05, 0x02, 0x02, 0x00]).is_err());
}
#[test]
fn ec2_public_cose_key_splits_fixed_length_coordinates() {
let mut point = vec![0x04];
point.extend_from_slice(&[0xaa; 32]);
point.extend_from_slice(&[0xbb; 32]);
let key = ec2_public_cose_key(iana::AlgorithmES256, &point, Some(b"p256")).unwrap();
assert_eq!(key.kty().unwrap(), Some(iana::KeyTypeEC2.into()));
assert_eq!(key.alg().unwrap(), Some(iana::AlgorithmES256.into()));
assert_eq!(key.kid().unwrap(), Some(&b"p256"[..]));
assert_eq!(
key.get_label(iana::EC2KeyParameterCrv).unwrap(),
Some(iana::EllipticCurveP_256.into())
);
assert_eq!(
key.get_bytes(iana::EC2KeyParameterX).unwrap(),
Some(&[0xaa; 32][..])
);
assert_eq!(
key.get_bytes(iana::EC2KeyParameterY).unwrap(),
Some(&[0xbb; 32][..])
);
assert!(ec2_public_cose_key(iana::AlgorithmES256, &point[..64], None).is_err());
let mut compressed = point.clone();
compressed[0] = 0x02;
assert!(ec2_public_cose_key(iana::AlgorithmES256, &compressed, None).is_err());
assert!(ec2_public_cose_key(iana::AlgorithmEdDSA, &point, None).is_err());
}
}