Skip to content

Commit

Permalink
Refactor and fix usage validation
Browse files Browse the repository at this point in the history
  • Loading branch information
richarddavison committed Dec 13, 2024
1 parent bfb08d9 commit 1f0e345
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 150 deletions.
66 changes: 39 additions & 27 deletions modules/llrt_crypto/src/sha_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
// SPDX-License-Identifier: Apache-2.0
use llrt_utils::{
bytes::{bytes_to_typed_array, ObjectBytes},
iterable_enum, str_enum,
iterable_enum,
result::ResultExt,
};
use ring::{
digest::{self, Context as DigestContext},
hmac::{self, Context as HmacContext},
};
use rquickjs::{function::Opt, prelude::This, Class, Ctx, Exception, Result, Value};
use rquickjs::{function::Opt, prelude::This, Class, Ctx, Result, Value};

use super::encoded_bytes;

Expand All @@ -23,18 +24,8 @@ pub struct Hmac {
impl Hmac {
#[qjs(skip)]
pub fn new<'js>(ctx: Ctx<'js>, algorithm: String, key_value: ObjectBytes<'js>) -> Result<Self> {
let algorithm = match algorithm.to_lowercase().as_str() {
"sha1" => hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
"sha256" => hmac::HMAC_SHA256,
"sha384" => hmac::HMAC_SHA384,
"sha512" => hmac::HMAC_SHA512,
_ => {
return Err(Exception::throw_message(
&ctx,
&["Algorithm \"", &algorithm, "\" not supported"].concat(),
))
},
};
let algorithm = ShaAlgorithm::try_from(algorithm.as_str()).or_throw(&ctx)?;
let algorithm = *algorithm.hmac_algorithm();

Ok(Self {
context: HmacContext::with_key(&hmac::Key::new(algorithm, key_value.as_bytes())),
Expand Down Expand Up @@ -81,18 +72,8 @@ pub struct Hash {
impl Hash {
#[qjs(skip)]
pub fn new(ctx: Ctx<'_>, algorithm: String) -> Result<Self> {
let algorithm = match algorithm.to_lowercase().as_str() {
"sha1" => &digest::SHA1_FOR_LEGACY_USE_ONLY,
"sha256" => &digest::SHA256,
"sha384" => &digest::SHA384,
"sha512" => &digest::SHA512,
_ => {
return Err(Exception::throw_message(
&ctx,
&["Algorithm \"", &algorithm, "\" not supported"].concat(),
))
},
};
let algorithm = ShaAlgorithm::try_from(algorithm.as_str()).or_throw(&ctx)?;
let algorithm = algorithm.digest_algorithm();

Ok(Self {
context: DigestContext::new(algorithm),
Expand Down Expand Up @@ -130,7 +111,6 @@ pub enum ShaAlgorithm {
}

iterable_enum!(ShaAlgorithm, SHA1, SHA256, SHA384, SHA512);
str_enum!(ShaAlgorithm, SHA1 => "SHA-1", SHA256 => "SHA-256", SHA384 => "SHA-384", SHA512 => "SHA-512");

impl ShaAlgorithm {
pub fn class_name(&self) -> &'static str {
Expand Down Expand Up @@ -158,6 +138,38 @@ impl ShaAlgorithm {
ShaAlgorithm::SHA512 => &digest::SHA512,
}
}

pub fn as_str(&self) -> &'static str {
match self {
ShaAlgorithm::SHA1 => "SHA-1",
ShaAlgorithm::SHA256 => "SHA-256",
ShaAlgorithm::SHA384 => "SHA-384",
ShaAlgorithm::SHA512 => "SHA-512",
}
}
}

impl TryFrom<&str> for ShaAlgorithm {
type Error = String;
fn try_from(s: &str) -> std::result::Result<Self, Self::Error> {
Ok(match s.to_ascii_uppercase().as_str() {
"SHA1" => ShaAlgorithm::SHA1,
"SHA-1" => ShaAlgorithm::SHA1,
"SHA256" => ShaAlgorithm::SHA256,
"SHA-256" => ShaAlgorithm::SHA256,
"SHA384" => ShaAlgorithm::SHA384,
"SHA-384" => ShaAlgorithm::SHA384,
"SHA512" => ShaAlgorithm::SHA512,
"SHA-512" => ShaAlgorithm::SHA512,
_ => return Err(["'", s, "' not available"].concat()),
})
}
}

impl AsRef<str> for ShaAlgorithm {
fn as_ref(&self) -> &str {
self.as_str()
}
}

#[rquickjs::class]
Expand Down
9 changes: 8 additions & 1 deletion modules/llrt_crypto/src/subtle/crypto_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ impl CryptoKey {
return Ok(());
}
}
Err(["CryptoKey doesn't support '", usage, "'"].concat())
Err([
"CryptoKey with '",
self.name.as_ref(),
"', doesn't support '",
usage,
"'",
]
.concat())
}
}
20 changes: 14 additions & 6 deletions modules/llrt_crypto/src/subtle/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rquickjs::{Array, ArrayBuffer, Class, Ctx, Exception, Result, Value};
use super::{
algorithm_not_supported_error,
derive_algorithm::DeriveAlgorithm,
key_algorithm::{classify_and_check_usages, KeyAlgorithm, KeyAlgorithmMode, KeyDerivation},
key_algorithm::{KeyAlgorithm, KeyAlgorithmMode, KeyAlgorithmWithUsages, KeyDerivation},
};

use crate::{
Expand Down Expand Up @@ -46,7 +46,7 @@ fn derive_bits(
length: u32,
) -> Result<Vec<u8>> {
Ok(match algorithm {
DeriveAlgorithm::Edch { curve, public } => match curve {
DeriveAlgorithm::Ecdh { curve, public } => match curve {
EllipticCurve::P256 => {
let secret_key = p256::SecretKey::from_pkcs8_der(base_key).or_throw(ctx)?;
let public_key = p256::SecretKey::from_pkcs8_der(public)
Expand Down Expand Up @@ -127,8 +127,18 @@ pub async fn subtle_derive_key<'js>(
extractable: bool,
key_usages: Array<'js>,
) -> Result<Class<'js, CryptoKey>> {
let (derived_key_algorithm, name) =
KeyAlgorithm::from_js(&ctx, KeyAlgorithmMode::Derive, derived_key_algorithm)?;
let KeyAlgorithmWithUsages {
algorithm: derived_key_algorithm,
name,
public_usages,
..
} = KeyAlgorithm::from_js(
&ctx,
KeyAlgorithmMode::Derive,
derived_key_algorithm,
key_usages,
)?;

let length: u16 = match &derived_key_algorithm {
KeyAlgorithm::Aes { length } => *length,
KeyAlgorithm::Hmac { length, .. } => *length,
Expand All @@ -138,8 +148,6 @@ pub async fn subtle_derive_key<'js>(
},
};

let (_, public_usages) = classify_and_check_usages(&ctx, &name, &key_usages)?;

let handle = &base_key.borrow().handle;

let bytes = derive_bits(&ctx, &algorithm, handle, length as u32)?;
Expand Down
8 changes: 4 additions & 4 deletions modules/llrt_crypto/src/subtle/derive_algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::{

#[derive(Debug)]
pub enum DeriveAlgorithm {
Edch {
Ecdh {
curve: EllipticCurve,
public: Rc<[u8]>,
},
Expand All @@ -24,7 +24,7 @@ impl<'js> FromJs<'js> for DeriveAlgorithm {
let name: String = obj.get_required("name", "algorithm")?;

Ok(match name.as_str() {
"ECDH" => {
"ECDH" | "X25519" => {
let public_key: Class<CryptoKey> = obj.get_required("public", "algorithm")?;
let public_key = public_key.borrow();
let curve = if let KeyAlgorithm::Ec { curve } = &public_key.algorithm {
Expand All @@ -36,7 +36,7 @@ impl<'js> FromJs<'js> for DeriveAlgorithm {
));
};

DeriveAlgorithm::Edch {
DeriveAlgorithm::Ecdh {
curve,
public: public_key.handle.clone(),
}
Expand All @@ -46,7 +46,7 @@ impl<'js> FromJs<'js> for DeriveAlgorithm {
_ => {
return Err(Exception::throw_message(
ctx,
"Algorithm 'name' must be ECDH | HKDF | PBKDF2",
"Algorithm 'name' must be X25519 | ECDH | HKDF | PBKDF2",
))
},
})
Expand Down
10 changes: 7 additions & 3 deletions modules/llrt_crypto/src/subtle/generate_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{sha_hash::ShaAlgorithm, CryptoKey, SYSTEM_RANDOM};

use super::{
algorithm_not_supported_error,
key_algorithm::{classify_and_check_usages, KeyAlgorithm, KeyAlgorithmMode},
key_algorithm::{KeyAlgorithm, KeyAlgorithmMode, KeyAlgorithmWithUsages},
};

pub async fn subtle_generate_key<'js>(
Expand All @@ -24,9 +24,13 @@ pub async fn subtle_generate_key<'js>(
extractable: bool,
key_usages: Array<'js>,
) -> Result<Value<'js>> {
let (key_algorithm, name) = KeyAlgorithm::from_js(&ctx, KeyAlgorithmMode::Generate, algorithm)?;
let KeyAlgorithmWithUsages {
name,
algorithm: key_algorithm,
private_usages,
public_usages,
} = KeyAlgorithm::from_js(&ctx, KeyAlgorithmMode::Generate, algorithm, key_usages)?;

let (private_usages, public_usages) = classify_and_check_usages(&ctx, &name, &key_usages)?;
let bytes = generate_key(&ctx, &key_algorithm)?;

if matches!(
Expand Down
11 changes: 7 additions & 4 deletions modules/llrt_crypto/src/subtle/import_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rquickjs::{Array, Class, Ctx, Exception, Result, Value};

use crate::subtle::CryptoKey;

use super::key_algorithm::{classify_and_check_usages, KeyAlgorithm, KeyAlgorithmMode};
use super::key_algorithm::{KeyAlgorithm, KeyAlgorithmMode, KeyAlgorithmWithUsages};

pub async fn subtle_import_key<'js>(
ctx: Ctx<'js>,
Expand Down Expand Up @@ -37,9 +37,12 @@ pub async fn subtle_import_key<'js>(
}
}

let (key_algorithm, name) = KeyAlgorithm::from_js(&ctx, KeyAlgorithmMode::Import, algorithm)?;

let (_, public_usages) = classify_and_check_usages(&ctx, &name, &key_usages)?;
let KeyAlgorithmWithUsages {
name,
algorithm: key_algorithm,
public_usages,
..
} = KeyAlgorithm::from_js(&ctx, KeyAlgorithmMode::Import, algorithm, key_usages)?;

Class::instance(
ctx,
Expand Down
Loading

0 comments on commit 1f0e345

Please sign in to comment.