summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorLeo Kettmeir <crowlkats@toaxl.com>2024-11-06 16:57:57 -0800
committerGitHub <noreply@github.com>2024-11-06 16:57:57 -0800
commit1cab4f07a3e6125a089726f022dd6bc9af517536 (patch)
tree574a4d128c107f42d8c4478a240e4a4c05611e7c /ext
parentdb53ec230d2de1b3be50230d4c00e83a03df686f (diff)
refactor: use concrete error type for remaining ops (#26746)
Diffstat (limited to 'ext')
-rw-r--r--ext/node/ops/crypto/cipher.rs145
-rw-r--r--ext/node/ops/crypto/digest.rs30
-rw-r--r--ext/node/ops/crypto/keys.rs679
-rw-r--r--ext/node/ops/crypto/mod.rs414
-rw-r--r--ext/node/ops/crypto/sign.rs142
-rw-r--r--ext/node/ops/crypto/x509.rs66
6 files changed, 932 insertions, 544 deletions
diff --git a/ext/node/ops/crypto/cipher.rs b/ext/node/ops/crypto/cipher.rs
index b80aa33fe..ec45146b4 100644
--- a/ext/node/ops/crypto/cipher.rs
+++ b/ext/node/ops/crypto/cipher.rs
@@ -4,9 +4,6 @@ use aes::cipher::block_padding::Pkcs7;
use aes::cipher::BlockDecryptMut;
use aes::cipher::BlockEncryptMut;
use aes::cipher::KeyIvInit;
-use deno_core::error::range_error;
-use deno_core::error::type_error;
-use deno_core::error::AnyError;
use deno_core::Resource;
use digest::generic_array::GenericArray;
use digest::KeyInit;
@@ -50,8 +47,22 @@ pub struct DecipherContext {
decipher: Rc<RefCell<Decipher>>,
}
+#[derive(Debug, thiserror::Error)]
+pub enum CipherContextError {
+ #[error("Cipher context is already in use")]
+ ContextInUse,
+ #[error("{0}")]
+ Resource(deno_core::error::AnyError),
+ #[error(transparent)]
+ Cipher(#[from] CipherError),
+}
+
impl CipherContext {
- pub fn new(algorithm: &str, key: &[u8], iv: &[u8]) -> Result<Self, AnyError> {
+ pub fn new(
+ algorithm: &str,
+ key: &[u8],
+ iv: &[u8],
+ ) -> Result<Self, CipherContextError> {
Ok(Self {
cipher: Rc::new(RefCell::new(Cipher::new(algorithm, key, iv)?)),
})
@@ -74,16 +85,31 @@ impl CipherContext {
auto_pad: bool,
input: &[u8],
output: &mut [u8],
- ) -> Result<Tag, AnyError> {
+ ) -> Result<Tag, CipherContextError> {
Rc::try_unwrap(self.cipher)
- .map_err(|_| type_error("Cipher context is already in use"))?
+ .map_err(|_| CipherContextError::ContextInUse)?
.into_inner()
.r#final(auto_pad, input, output)
+ .map_err(Into::into)
}
}
+#[derive(Debug, thiserror::Error)]
+pub enum DecipherContextError {
+ #[error("Decipher context is already in use")]
+ ContextInUse,
+ #[error("{0}")]
+ Resource(deno_core::error::AnyError),
+ #[error(transparent)]
+ Decipher(#[from] DecipherError),
+}
+
impl DecipherContext {
- pub fn new(algorithm: &str, key: &[u8], iv: &[u8]) -> Result<Self, AnyError> {
+ pub fn new(
+ algorithm: &str,
+ key: &[u8],
+ iv: &[u8],
+ ) -> Result<Self, DecipherContextError> {
Ok(Self {
decipher: Rc::new(RefCell::new(Decipher::new(algorithm, key, iv)?)),
})
@@ -103,11 +129,12 @@ impl DecipherContext {
input: &[u8],
output: &mut [u8],
auth_tag: &[u8],
- ) -> Result<(), AnyError> {
+ ) -> Result<(), DecipherContextError> {
Rc::try_unwrap(self.decipher)
- .map_err(|_| type_error("Decipher context is already in use"))?
+ .map_err(|_| DecipherContextError::ContextInUse)?
.into_inner()
.r#final(auto_pad, input, output, auth_tag)
+ .map_err(Into::into)
}
}
@@ -123,12 +150,26 @@ impl Resource for DecipherContext {
}
}
+#[derive(Debug, thiserror::Error)]
+pub enum CipherError {
+ #[error("IV length must be 12 bytes")]
+ InvalidIvLength,
+ #[error("Invalid key length")]
+ InvalidKeyLength,
+ #[error("Invalid initialization vector")]
+ InvalidInitializationVector,
+ #[error("Cannot pad the input data")]
+ CannotPadInputData,
+ #[error("Unknown cipher {0}")]
+ UnknownCipher(String),
+}
+
impl Cipher {
fn new(
algorithm_name: &str,
key: &[u8],
iv: &[u8],
- ) -> Result<Self, AnyError> {
+ ) -> Result<Self, CipherError> {
use Cipher::*;
Ok(match algorithm_name {
"aes-128-cbc" => {
@@ -139,7 +180,7 @@ impl Cipher {
"aes-256-ecb" => Aes256Ecb(Box::new(ecb::Encryptor::new(key.into()))),
"aes-128-gcm" => {
if iv.len() != 12 {
- return Err(type_error("IV length must be 12 bytes"));
+ return Err(CipherError::InvalidIvLength);
}
let cipher =
@@ -149,7 +190,7 @@ impl Cipher {
}
"aes-256-gcm" => {
if iv.len() != 12 {
- return Err(type_error("IV length must be 12 bytes"));
+ return Err(CipherError::InvalidIvLength);
}
let cipher =
@@ -159,15 +200,15 @@ impl Cipher {
}
"aes256" | "aes-256-cbc" => {
if key.len() != 32 {
- return Err(range_error("Invalid key length"));
+ return Err(CipherError::InvalidKeyLength);
}
if iv.len() != 16 {
- return Err(type_error("Invalid initialization vector"));
+ return Err(CipherError::InvalidInitializationVector);
}
Aes256Cbc(Box::new(cbc::Encryptor::new(key.into(), iv.into())))
}
- _ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),
+ _ => return Err(CipherError::UnknownCipher(algorithm_name.to_string())),
})
}
@@ -235,14 +276,14 @@ impl Cipher {
auto_pad: bool,
input: &[u8],
output: &mut [u8],
- ) -> Result<Tag, AnyError> {
+ ) -> Result<Tag, CipherError> {
assert!(input.len() < 16);
use Cipher::*;
match (self, auto_pad) {
(Aes128Cbc(encryptor), true) => {
let _ = (*encryptor)
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot pad the input data"))?;
+ .map_err(|_| CipherError::CannotPadInputData)?;
Ok(None)
}
(Aes128Cbc(mut encryptor), false) => {
@@ -255,7 +296,7 @@ impl Cipher {
(Aes128Ecb(encryptor), true) => {
let _ = (*encryptor)
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot pad the input data"))?;
+ .map_err(|_| CipherError::CannotPadInputData)?;
Ok(None)
}
(Aes128Ecb(mut encryptor), false) => {
@@ -268,7 +309,7 @@ impl Cipher {
(Aes192Ecb(encryptor), true) => {
let _ = (*encryptor)
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot pad the input data"))?;
+ .map_err(|_| CipherError::CannotPadInputData)?;
Ok(None)
}
(Aes192Ecb(mut encryptor), false) => {
@@ -281,7 +322,7 @@ impl Cipher {
(Aes256Ecb(encryptor), true) => {
let _ = (*encryptor)
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot pad the input data"))?;
+ .map_err(|_| CipherError::CannotPadInputData)?;
Ok(None)
}
(Aes256Ecb(mut encryptor), false) => {
@@ -296,7 +337,7 @@ impl Cipher {
(Aes256Cbc(encryptor), true) => {
let _ = (*encryptor)
.encrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot pad the input data"))?;
+ .map_err(|_| CipherError::CannotPadInputData)?;
Ok(None)
}
(Aes256Cbc(mut encryptor), false) => {
@@ -319,12 +360,32 @@ impl Cipher {
}
}
+#[derive(Debug, thiserror::Error)]
+pub enum DecipherError {
+ #[error("IV length must be 12 bytes")]
+ InvalidIvLength,
+ #[error("Invalid key length")]
+ InvalidKeyLength,
+ #[error("Invalid initialization vector")]
+ InvalidInitializationVector,
+ #[error("Cannot unpad the input data")]
+ CannotUnpadInputData,
+ #[error("Failed to authenticate data")]
+ DataAuthenticationFailed,
+ #[error("setAutoPadding(false) not supported for Aes128Gcm yet")]
+ SetAutoPaddingFalseAes128GcmUnsupported,
+ #[error("setAutoPadding(false) not supported for Aes256Gcm yet")]
+ SetAutoPaddingFalseAes256GcmUnsupported,
+ #[error("Unknown cipher {0}")]
+ UnknownCipher(String),
+}
+
impl Decipher {
fn new(
algorithm_name: &str,
key: &[u8],
iv: &[u8],
- ) -> Result<Self, AnyError> {
+ ) -> Result<Self, DecipherError> {
use Decipher::*;
Ok(match algorithm_name {
"aes-128-cbc" => {
@@ -335,7 +396,7 @@ impl Decipher {
"aes-256-ecb" => Aes256Ecb(Box::new(ecb::Decryptor::new(key.into()))),
"aes-128-gcm" => {
if iv.len() != 12 {
- return Err(type_error("IV length must be 12 bytes"));
+ return Err(DecipherError::InvalidIvLength);
}
let decipher =
@@ -345,7 +406,7 @@ impl Decipher {
}
"aes-256-gcm" => {
if iv.len() != 12 {
- return Err(type_error("IV length must be 12 bytes"));
+ return Err(DecipherError::InvalidIvLength);
}
let decipher =
@@ -355,15 +416,17 @@ impl Decipher {
}
"aes256" | "aes-256-cbc" => {
if key.len() != 32 {
- return Err(range_error("Invalid key length"));
+ return Err(DecipherError::InvalidKeyLength);
}
if iv.len() != 16 {
- return Err(type_error("Invalid initialization vector"));
+ return Err(DecipherError::InvalidInitializationVector);
}
Aes256Cbc(Box::new(cbc::Decryptor::new(key.into(), iv.into())))
}
- _ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),
+ _ => {
+ return Err(DecipherError::UnknownCipher(algorithm_name.to_string()))
+ }
})
}
@@ -432,14 +495,14 @@ impl Decipher {
input: &[u8],
output: &mut [u8],
auth_tag: &[u8],
- ) -> Result<(), AnyError> {
+ ) -> Result<(), DecipherError> {
use Decipher::*;
match (self, auto_pad) {
(Aes128Cbc(decryptor), true) => {
assert!(input.len() == 16);
let _ = (*decryptor)
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot unpad the input data"))?;
+ .map_err(|_| DecipherError::CannotUnpadInputData)?;
Ok(())
}
(Aes128Cbc(mut decryptor), false) => {
@@ -453,7 +516,7 @@ impl Decipher {
assert!(input.len() == 16);
let _ = (*decryptor)
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot unpad the input data"))?;
+ .map_err(|_| DecipherError::CannotUnpadInputData)?;
Ok(())
}
(Aes128Ecb(mut decryptor), false) => {
@@ -467,7 +530,7 @@ impl Decipher {
assert!(input.len() == 16);
let _ = (*decryptor)
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot unpad the input data"))?;
+ .map_err(|_| DecipherError::CannotUnpadInputData)?;
Ok(())
}
(Aes192Ecb(mut decryptor), false) => {
@@ -481,7 +544,7 @@ impl Decipher {
assert!(input.len() == 16);
let _ = (*decryptor)
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot unpad the input data"))?;
+ .map_err(|_| DecipherError::CannotUnpadInputData)?;
Ok(())
}
(Aes256Ecb(mut decryptor), false) => {
@@ -496,28 +559,28 @@ impl Decipher {
if tag.as_slice() == auth_tag {
Ok(())
} else {
- Err(type_error("Failed to authenticate data"))
+ Err(DecipherError::DataAuthenticationFailed)
}
}
- (Aes128Gcm(_), false) => Err(type_error(
- "setAutoPadding(false) not supported for Aes256Gcm yet",
- )),
+ (Aes128Gcm(_), false) => {
+ Err(DecipherError::SetAutoPaddingFalseAes128GcmUnsupported)
+ }
(Aes256Gcm(decipher), true) => {
let tag = decipher.finish();
if tag.as_slice() == auth_tag {
Ok(())
} else {
- Err(type_error("Failed to authenticate data"))
+ Err(DecipherError::DataAuthenticationFailed)
}
}
- (Aes256Gcm(_), false) => Err(type_error(
- "setAutoPadding(false) not supported for Aes256Gcm yet",
- )),
+ (Aes256Gcm(_), false) => {
+ Err(DecipherError::SetAutoPaddingFalseAes256GcmUnsupported)
+ }
(Aes256Cbc(decryptor), true) => {
assert!(input.len() == 16);
let _ = (*decryptor)
.decrypt_padded_b2b_mut::<Pkcs7>(input, output)
- .map_err(|_| type_error("Cannot unpad the input data"))?;
+ .map_err(|_| DecipherError::CannotUnpadInputData)?;
Ok(())
}
(Aes256Cbc(mut decryptor), false) => {
diff --git a/ext/node/ops/crypto/digest.rs b/ext/node/ops/crypto/digest.rs
index 293e8e063..a7d8fb51f 100644
--- a/ext/node/ops/crypto/digest.rs
+++ b/ext/node/ops/crypto/digest.rs
@@ -1,6 +1,4 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-use deno_core::error::generic_error;
-use deno_core::error::AnyError;
use deno_core::GarbageCollected;
use digest::Digest;
use digest::DynDigest;
@@ -19,7 +17,7 @@ impl Hasher {
pub fn new(
algorithm: &str,
output_length: Option<usize>,
- ) -> Result<Self, AnyError> {
+ ) -> Result<Self, HashError> {
let hash = Hash::new(algorithm, output_length)?;
Ok(Self {
@@ -44,7 +42,7 @@ impl Hasher {
pub fn clone_inner(
&self,
output_length: Option<usize>,
- ) -> Result<Option<Self>, AnyError> {
+ ) -> Result<Option<Self>, HashError> {
let hash = self.hash.borrow();
let Some(hash) = hash.as_ref() else {
return Ok(None);
@@ -184,11 +182,19 @@ pub enum Hash {
use Hash::*;
+#[derive(Debug, thiserror::Error)]
+pub enum HashError {
+ #[error("Output length mismatch for non-extendable algorithm")]
+ OutputLengthMismatch,
+ #[error("Digest method not supported: {0}")]
+ DigestMethodUnsupported(String),
+}
+
impl Hash {
pub fn new(
algorithm_name: &str,
output_length: Option<usize>,
- ) -> Result<Self, AnyError> {
+ ) -> Result<Self, HashError> {
match algorithm_name {
"shake128" => return Ok(Shake128(Default::default(), output_length)),
"shake256" => return Ok(Shake256(Default::default(), output_length)),
@@ -201,17 +207,13 @@ impl Hash {
let digest: D = Digest::new();
if let Some(length) = output_length {
if length != digest.output_size() {
- return Err(generic_error(
- "Output length mismatch for non-extendable algorithm",
- ));
+ return Err(HashError::OutputLengthMismatch);
}
}
FixedSize(Box::new(digest))
},
_ => {
- return Err(generic_error(format!(
- "Digest method not supported: {algorithm_name}"
- )))
+ return Err(HashError::DigestMethodUnsupported(algorithm_name.to_string()))
}
);
@@ -243,14 +245,12 @@ impl Hash {
pub fn clone_hash(
&self,
output_length: Option<usize>,
- ) -> Result<Self, AnyError> {
+ ) -> Result<Self, HashError> {
let hash = match self {
FixedSize(context) => {
if let Some(length) = output_length {
if length != context.output_size() {
- return Err(generic_error(
- "Output length mismatch for non-extendable algorithm",
- ));
+ return Err(HashError::OutputLengthMismatch);
}
}
FixedSize(context.box_clone())
diff --git a/ext/node/ops/crypto/keys.rs b/ext/node/ops/crypto/keys.rs
index ac62f5cca..f164972d4 100644
--- a/ext/node/ops/crypto/keys.rs
+++ b/ext/node/ops/crypto/keys.rs
@@ -4,9 +4,7 @@ use std::borrow::Cow;
use std::cell::RefCell;
use base64::Engine;
-use deno_core::error::generic_error;
use deno_core::error::type_error;
-use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::serde_v8::BigInt as V8BigInt;
use deno_core::unsync::spawn_blocking;
@@ -46,6 +44,7 @@ use spki::der::Reader as _;
use spki::DecodePublicKey as _;
use spki::EncodePublicKey as _;
use spki::SubjectPublicKeyInfoRef;
+use x509_parser::error::X509Error;
use x509_parser::x509;
use super::dh;
@@ -236,9 +235,11 @@ impl RsaPssPrivateKey {
}
impl EcPublicKey {
- pub fn to_jwk(&self) -> Result<elliptic_curve::JwkEcKey, AnyError> {
+ pub fn to_jwk(&self) -> Result<JwkEcKey, AsymmetricPublicKeyJwkError> {
match self {
- EcPublicKey::P224(_) => Err(type_error("Unsupported JWK EC curve: P224")),
+ EcPublicKey::P224(_) => {
+ Err(AsymmetricPublicKeyJwkError::UnsupportedJwkEcCurveP224)
+ }
EcPublicKey::P256(key) => Ok(key.to_jwk()),
EcPublicKey::P384(key) => Ok(key.to_jwk()),
}
@@ -363,49 +364,201 @@ impl<'a> TryFrom<rsa::pkcs8::der::asn1::AnyRef<'a>> for RsaPssParameters<'a> {
}
}
+#[derive(Debug, thiserror::Error)]
+pub enum X509PublicKeyError {
+ #[error(transparent)]
+ X509(#[from] x509_parser::error::X509Error),
+ #[error(transparent)]
+ Rsa(#[from] rsa::Error),
+ #[error(transparent)]
+ Asn1(#[from] x509_parser::der_parser::asn1_rs::Error),
+ #[error(transparent)]
+ Ec(#[from] elliptic_curve::Error),
+ #[error("unsupported ec named curve")]
+ UnsupportedEcNamedCurve,
+ #[error("missing ec parameters")]
+ MissingEcParameters,
+ #[error("malformed DSS public key")]
+ MalformedDssPublicKey,
+ #[error("unsupported x509 public key type")]
+ UnsupportedX509KeyType,
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum RsaJwkError {
+ #[error(transparent)]
+ Base64(#[from] base64::DecodeError),
+ #[error(transparent)]
+ Rsa(#[from] rsa::Error),
+ #[error("missing RSA private component")]
+ MissingRsaPrivateComponent,
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum EcJwkError {
+ #[error(transparent)]
+ Ec(#[from] elliptic_curve::Error),
+ #[error("unsupported curve: {0}")]
+ UnsupportedCurve(String),
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum EdRawError {
+ #[error(transparent)]
+ Ed25519Signature(#[from] ed25519_dalek::SignatureError),
+ #[error("invalid Ed25519 key")]
+ InvalidEd25519Key,
+ #[error("unsupported curve")]
+ UnsupportedCurve,
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum AsymmetricPrivateKeyError {
+ #[error("invalid PEM private key: not valid utf8 starting at byte {0}")]
+ InvalidPemPrivateKeyInvalidUtf8(usize),
+ #[error("invalid encrypted PEM private key")]
+ InvalidEncryptedPemPrivateKey,
+ #[error("invalid PEM private key")]
+ InvalidPemPrivateKey,
+ #[error("encrypted private key requires a passphrase to decrypt")]
+ EncryptedPrivateKeyRequiresPassphraseToDecrypt,
+ #[error("invalid PKCS#1 private key")]
+ InvalidPkcs1PrivateKey,
+ #[error("invalid SEC1 private key")]
+ InvalidSec1PrivateKey,
+ #[error("unsupported PEM label: {0}")]
+ UnsupportedPemLabel(String),
+ #[error(transparent)]
+ RsaPssParamsParse(#[from] RsaPssParamsParseError),
+ #[error("invalid encrypted PKCS#8 private key")]
+ InvalidEncryptedPkcs8PrivateKey,
+ #[error("invalid PKCS#8 private key")]
+ InvalidPkcs8PrivateKey,
+ #[error("PKCS#1 private key does not support encryption with passphrase")]
+ Pkcs1PrivateKeyDoesNotSupportEncryptionWithPassphrase,
+ #[error("SEC1 private key does not support encryption with passphrase")]
+ Sec1PrivateKeyDoesNotSupportEncryptionWithPassphrase,
+ #[error("unsupported ec named curve")]
+ UnsupportedEcNamedCurve,
+ #[error("invalid private key")]
+ InvalidPrivateKey,
+ #[error("invalid DSA private key")]
+ InvalidDsaPrivateKey,
+ #[error("malformed or missing named curve in ec parameters")]
+ MalformedOrMissingNamedCurveInEcParameters,
+ #[error("unsupported key type: {0}")]
+ UnsupportedKeyType(String),
+ #[error("unsupported key format: {0}")]
+ UnsupportedKeyFormat(String),
+ #[error("invalid x25519 private key")]
+ InvalidX25519PrivateKey,
+ #[error("x25519 private key is the wrong length")]
+ X25519PrivateKeyIsWrongLength,
+ #[error("invalid Ed25519 private key")]
+ InvalidEd25519PrivateKey,
+ #[error("missing dh parameters")]
+ MissingDhParameters,
+ #[error("unsupported private key oid")]
+ UnsupportedPrivateKeyOid,
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum AsymmetricPublicKeyError {
+ #[error("invalid PEM private key: not valid utf8 starting at byte {0}")]
+ InvalidPemPrivateKeyInvalidUtf8(usize),
+ #[error("invalid PEM public key")]
+ InvalidPemPublicKey,
+ #[error("invalid PKCS#1 public key")]
+ InvalidPkcs1PublicKey,
+ #[error(transparent)]
+ AsymmetricPrivateKey(#[from] AsymmetricPrivateKeyError),
+ #[error("invalid x509 certificate")]
+ InvalidX509Certificate,
+ #[error(transparent)]
+ X509(#[from] x509_parser::nom::Err<X509Error>),
+ #[error(transparent)]
+ X509PublicKey(#[from] X509PublicKeyError),
+ #[error("unsupported PEM label: {0}")]
+ UnsupportedPemLabel(String),
+ #[error("invalid SPKI public key")]
+ InvalidSpkiPublicKey,
+ #[error("unsupported key type: {0}")]
+ UnsupportedKeyType(String),
+ #[error("unsupported key format: {0}")]
+ UnsupportedKeyFormat(String),
+ #[error(transparent)]
+ Spki(#[from] spki::Error),
+ #[error(transparent)]
+ Pkcs1(#[from] rsa::pkcs1::Error),
+ #[error(transparent)]
+ RsaPssParamsParse(#[from] RsaPssParamsParseError),
+ #[error("malformed DSS public key")]
+ MalformedDssPublicKey,
+ #[error("malformed or missing named curve in ec parameters")]
+ MalformedOrMissingNamedCurveInEcParameters,
+ #[error("malformed or missing public key in ec spki")]
+ MalformedOrMissingPublicKeyInEcSpki,
+ #[error(transparent)]
+ Ec(#[from] elliptic_curve::Error),
+ #[error("unsupported ec named curve")]
+ UnsupportedEcNamedCurve,
+ #[error("malformed or missing public key in x25519 spki")]
+ MalformedOrMissingPublicKeyInX25519Spki,
+ #[error("x25519 public key is too short")]
+ X25519PublicKeyIsTooShort,
+ #[error("invalid Ed25519 public key")]
+ InvalidEd25519PublicKey,
+ #[error("missing dh parameters")]
+ MissingDhParameters,
+ #[error("malformed dh parameters")]
+ MalformedDhParameters,
+ #[error("malformed or missing public key in dh spki")]
+ MalformedOrMissingPublicKeyInDhSpki,
+ #[error("unsupported private key oid")]
+ UnsupportedPrivateKeyOid,
+}
+
impl KeyObjectHandle {
pub fn new_asymmetric_private_key_from_js(
key: &[u8],
format: &str,
typ: &str,
passphrase: Option<&[u8]>,
- ) -> Result<KeyObjectHandle, AnyError> {
+ ) -> Result<KeyObjectHandle, AsymmetricPrivateKeyError> {
let document = match format {
"pem" => {
let pem = std::str::from_utf8(key).map_err(|err| {
- type_error(format!(
- "invalid PEM private key: not valid utf8 starting at byte {}",
- err.valid_up_to()
- ))
+ AsymmetricPrivateKeyError::InvalidPemPrivateKeyInvalidUtf8(
+ err.valid_up_to(),
+ )
})?;
if let Some(passphrase) = passphrase {
- SecretDocument::from_pkcs8_encrypted_pem(pem, passphrase)
- .map_err(|_| type_error("invalid encrypted PEM private key"))?
+ SecretDocument::from_pkcs8_encrypted_pem(pem, passphrase).map_err(
+ |_| AsymmetricPrivateKeyError::InvalidEncryptedPemPrivateKey,
+ )?
} else {
let (label, doc) = SecretDocument::from_pem(pem)
- .map_err(|_| type_error("invalid PEM private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidPemPrivateKey)?;
match label {
EncryptedPrivateKeyInfo::PEM_LABEL => {
- return Err(type_error(
- "encrypted private key requires a passphrase to decrypt",
- ))
+ return Err(AsymmetricPrivateKeyError::EncryptedPrivateKeyRequiresPassphraseToDecrypt);
}
PrivateKeyInfo::PEM_LABEL => doc,
rsa::pkcs1::RsaPrivateKey::PEM_LABEL => {
- SecretDocument::from_pkcs1_der(doc.as_bytes())
- .map_err(|_| type_error("invalid PKCS#1 private key"))?
+ SecretDocument::from_pkcs1_der(doc.as_bytes()).map_err(|_| {
+ AsymmetricPrivateKeyError::InvalidPkcs1PrivateKey
+ })?
}
sec1::EcPrivateKey::PEM_LABEL => {
SecretDocument::from_sec1_der(doc.as_bytes())
- .map_err(|_| type_error("invalid SEC1 private key"))?
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidSec1PrivateKey)?
}
_ => {
- return Err(type_error(format!(
- "unsupported PEM label: {}",
- label
- )))
+ return Err(AsymmetricPrivateKeyError::UnsupportedPemLabel(
+ label.to_string(),
+ ))
}
}
}
@@ -413,54 +566,57 @@ impl KeyObjectHandle {
"der" => match typ {
"pkcs8" => {
if let Some(passphrase) = passphrase {
- SecretDocument::from_pkcs8_encrypted_der(key, passphrase)
- .map_err(|_| type_error("invalid encrypted PKCS#8 private key"))?
+ SecretDocument::from_pkcs8_encrypted_der(key, passphrase).map_err(
+ |_| AsymmetricPrivateKeyError::InvalidEncryptedPkcs8PrivateKey,
+ )?
} else {
SecretDocument::from_pkcs8_der(key)
- .map_err(|_| type_error("invalid PKCS#8 private key"))?
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidPkcs8PrivateKey)?
}
}
"pkcs1" => {
if passphrase.is_some() {
- return Err(type_error(
- "PKCS#1 private key does not support encryption with passphrase",
- ));
+ return Err(AsymmetricPrivateKeyError::Pkcs1PrivateKeyDoesNotSupportEncryptionWithPassphrase);
}
SecretDocument::from_pkcs1_der(key)
- .map_err(|_| type_error("invalid PKCS#1 private key"))?
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidPkcs1PrivateKey)?
}
"sec1" => {
if passphrase.is_some() {
- return Err(type_error(
- "SEC1 private key does not support encryption with passphrase",
- ));
+ return Err(AsymmetricPrivateKeyError::Sec1PrivateKeyDoesNotSupportEncryptionWithPassphrase);
}
SecretDocument::from_sec1_der(key)
- .map_err(|_| type_error("invalid SEC1 private key"))?
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidSec1PrivateKey)?
+ }
+ _ => {
+ return Err(AsymmetricPrivateKeyError::UnsupportedKeyType(
+ typ.to_string(),
+ ))
}
- _ => return Err(type_error(format!("unsupported key type: {}", typ))),
},
_ => {
- return Err(type_error(format!("unsupported key format: {}", format)))
+ return Err(AsymmetricPrivateKeyError::UnsupportedKeyFormat(
+ format.to_string(),
+ ))
}
};
let pk_info = PrivateKeyInfo::try_from(document.as_bytes())
- .map_err(|_| type_error("invalid private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidPrivateKey)?;
let alg = pk_info.algorithm.oid;
let private_key = match alg {
RSA_ENCRYPTION_OID => {
let private_key =
rsa::RsaPrivateKey::from_pkcs1_der(pk_info.private_key)
- .map_err(|_| type_error("invalid PKCS#1 private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidPkcs1PrivateKey)?;
AsymmetricPrivateKey::Rsa(private_key)
}
RSASSA_PSS_OID => {
let details = parse_rsa_pss_params(pk_info.algorithm.parameters)?;
let private_key =
rsa::RsaPrivateKey::from_pkcs1_der(pk_info.private_key)
- .map_err(|_| type_error("invalid PKCS#1 private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidPkcs1PrivateKey)?;
AsymmetricPrivateKey::RsaPss(RsaPssPrivateKey {
key: private_key,
details,
@@ -468,40 +624,43 @@ impl KeyObjectHandle {
}
DSA_OID => {
let private_key = dsa::SigningKey::try_from(pk_info)
- .map_err(|_| type_error("invalid DSA private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidDsaPrivateKey)?;
AsymmetricPrivateKey::Dsa(private_key)
}
EC_OID => {
let named_curve = pk_info.algorithm.parameters_oid().map_err(|_| {
- type_error("malformed or missing named curve in ec parameters")
+ AsymmetricPrivateKeyError::MalformedOrMissingNamedCurveInEcParameters
})?;
match named_curve {
ID_SECP224R1_OID => {
- let secret_key =
- p224::SecretKey::from_sec1_der(pk_info.private_key)
- .map_err(|_| type_error("invalid SEC1 private key"))?;
+ let secret_key = p224::SecretKey::from_sec1_der(
+ pk_info.private_key,
+ )
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidSec1PrivateKey)?;
AsymmetricPrivateKey::Ec(EcPrivateKey::P224(secret_key))
}
ID_SECP256R1_OID => {
- let secret_key =
- p256::SecretKey::from_sec1_der(pk_info.private_key)
- .map_err(|_| type_error("invalid SEC1 private key"))?;
+ let secret_key = p256::SecretKey::from_sec1_der(
+ pk_info.private_key,
+ )
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidSec1PrivateKey)?;
AsymmetricPrivateKey::Ec(EcPrivateKey::P256(secret_key))
}
ID_SECP384R1_OID => {
- let secret_key =
- p384::SecretKey::from_sec1_der(pk_info.private_key)
- .map_err(|_| type_error("invalid SEC1 private key"))?;
+ let secret_key = p384::SecretKey::from_sec1_der(
+ pk_info.private_key,
+ )
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidSec1PrivateKey)?;
AsymmetricPrivateKey::Ec(EcPrivateKey::P384(secret_key))
}
- _ => return Err(type_error("unsupported ec named curve")),
+ _ => return Err(AsymmetricPrivateKeyError::UnsupportedEcNamedCurve),
}
}
X25519_OID => {
let string_ref = OctetStringRef::from_der(pk_info.private_key)
- .map_err(|_| type_error("invalid x25519 private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidX25519PrivateKey)?;
if string_ref.as_bytes().len() != 32 {
- return Err(type_error("x25519 private key is the wrong length"));
+ return Err(AsymmetricPrivateKeyError::X25519PrivateKeyIsWrongLength);
}
let mut bytes = [0; 32];
bytes.copy_from_slice(string_ref.as_bytes());
@@ -509,22 +668,22 @@ impl KeyObjectHandle {
}
ED25519_OID => {
let signing_key = ed25519_dalek::SigningKey::try_from(pk_info)
- .map_err(|_| type_error("invalid Ed25519 private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyError::InvalidEd25519PrivateKey)?;
AsymmetricPrivateKey::Ed25519(signing_key)
}
DH_KEY_AGREEMENT_OID => {
let params = pk_info
.algorithm
.parameters
- .ok_or_else(|| type_error("missing dh parameters"))?;
+ .ok_or(AsymmetricPrivateKeyError::MissingDhParameters)?;
let params = pkcs3::DhParameter::from_der(&params.to_der().unwrap())
- .map_err(|_| type_error("malformed dh parameters"))?;
+ .map_err(|_| AsymmetricPrivateKeyError::MissingDhParameters)?;
AsymmetricPrivateKey::Dh(DhPrivateKey {
key: dh::PrivateKey::from_bytes(pk_info.private_key),
params,
})
}
- _ => return Err(type_error("unsupported private key oid")),
+ _ => return Err(AsymmetricPrivateKeyError::UnsupportedPrivateKeyOid),
};
Ok(KeyObjectHandle::AsymmetricPrivate(private_key))
@@ -532,7 +691,7 @@ impl KeyObjectHandle {
pub fn new_x509_public_key(
spki: &x509::SubjectPublicKeyInfo,
- ) -> Result<KeyObjectHandle, AnyError> {
+ ) -> Result<KeyObjectHandle, X509PublicKeyError> {
use x509_parser::der_parser::asn1_rs::oid;
use x509_parser::public_key::PublicKey;
@@ -565,18 +724,18 @@ impl KeyObjectHandle {
let public_key = p384::PublicKey::from_sec1_bytes(data)?;
AsymmetricPublicKey::Ec(EcPublicKey::P384(public_key))
}
- _ => return Err(type_error("unsupported ec named curve")),
+ _ => return Err(X509PublicKeyError::UnsupportedEcNamedCurve),
}
} else {
- return Err(type_error("missing ec parameters"));
+ return Err(X509PublicKeyError::MissingEcParameters);
}
}
PublicKey::DSA(_) => {
let verifying_key = dsa::VerifyingKey::from_public_key_der(spki.raw)
- .map_err(|_| type_error("malformed DSS public key"))?;
+ .map_err(|_| X509PublicKeyError::MalformedDssPublicKey)?;
AsymmetricPublicKey::Dsa(verifying_key)
}
- _ => return Err(type_error("unsupported x509 public key type")),
+ _ => return Err(X509PublicKeyError::UnsupportedX509KeyType),
};
Ok(KeyObjectHandle::AsymmetricPublic(key))
@@ -585,7 +744,7 @@ impl KeyObjectHandle {
pub fn new_rsa_jwk(
jwk: RsaJwkKey,
is_public: bool,
- ) -> Result<KeyObjectHandle, AnyError> {
+ ) -> Result<KeyObjectHandle, RsaJwkError> {
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
let n = BASE64_URL_SAFE_NO_PAD.decode(jwk.n.as_bytes())?;
@@ -604,19 +763,19 @@ impl KeyObjectHandle {
let d = BASE64_URL_SAFE_NO_PAD.decode(
jwk
.d
- .ok_or_else(|| type_error("missing RSA private component"))?
+ .ok_or(RsaJwkError::MissingRsaPrivateComponent)?
.as_bytes(),
)?;
let p = BASE64_URL_SAFE_NO_PAD.decode(
jwk
.p
- .ok_or_else(|| type_error("missing RSA private component"))?
+ .ok_or(RsaJwkError::MissingRsaPrivateComponent)?
.as_bytes(),
)?;
let q = BASE64_URL_SAFE_NO_PAD.decode(
jwk
.q
- .ok_or_else(|| type_error("missing RSA private component"))?
+ .ok_or(RsaJwkError::MissingRsaPrivateComponent)?
.as_bytes(),
)?;
@@ -640,7 +799,7 @@ impl KeyObjectHandle {
pub fn new_ec_jwk(
jwk: &JwkEcKey,
is_public: bool,
- ) -> Result<KeyObjectHandle, AnyError> {
+ ) -> Result<KeyObjectHandle, EcJwkError> {
// https://datatracker.ietf.org/doc/html/rfc7518#section-6.2.1.1
let handle = match jwk.crv() {
"P-256" if is_public => {
@@ -660,7 +819,7 @@ impl KeyObjectHandle {
EcPrivateKey::P384(p384::SecretKey::from_jwk(jwk)?),
)),
_ => {
- return Err(type_error(format!("unsupported curve: {}", jwk.crv())));
+ return Err(EcJwkError::UnsupportedCurve(jwk.crv().to_string()));
}
};
@@ -671,12 +830,11 @@ impl KeyObjectHandle {
curve: &str,
data: &[u8],
is_public: bool,
- ) -> Result<KeyObjectHandle, AnyError> {
+ ) -> Result<KeyObjectHandle, EdRawError> {
match curve {
"Ed25519" => {
- let data = data
- .try_into()
- .map_err(|_| type_error("invalid Ed25519 key"))?;
+ let data =
+ data.try_into().map_err(|_| EdRawError::InvalidEd25519Key)?;
if !is_public {
Ok(KeyObjectHandle::AsymmetricPrivate(
AsymmetricPrivateKey::Ed25519(
@@ -692,9 +850,8 @@ impl KeyObjectHandle {
}
}
"X25519" => {
- let data: [u8; 32] = data
- .try_into()
- .map_err(|_| type_error("invalid x25519 key"))?;
+ let data: [u8; 32] =
+ data.try_into().map_err(|_| EdRawError::InvalidEd25519Key)?;
if !is_public {
Ok(KeyObjectHandle::AsymmetricPrivate(
AsymmetricPrivateKey::X25519(x25519_dalek::StaticSecret::from(
@@ -707,7 +864,7 @@ impl KeyObjectHandle {
))
}
}
- _ => Err(type_error("unsupported curve")),
+ _ => Err(EdRawError::UnsupportedCurve),
}
}
@@ -716,24 +873,23 @@ impl KeyObjectHandle {
format: &str,
typ: &str,
passphrase: Option<&[u8]>,
- ) -> Result<KeyObjectHandle, AnyError> {
+ ) -> Result<KeyObjectHandle, AsymmetricPublicKeyError> {
let document = match format {
"pem" => {
let pem = std::str::from_utf8(key).map_err(|err| {
- type_error(format!(
- "invalid PEM public key: not valid utf8 starting at byte {}",
- err.valid_up_to()
- ))
+ AsymmetricPublicKeyError::InvalidPemPrivateKeyInvalidUtf8(
+ err.valid_up_to(),
+ )
})?;
let (label, document) = Document::from_pem(pem)
- .map_err(|_| type_error("invalid PEM public key"))?;
+ .map_err(|_| AsymmetricPublicKeyError::InvalidPemPublicKey)?;
match label {
SubjectPublicKeyInfoRef::PEM_LABEL => document,
rsa::pkcs1::RsaPublicKey::PEM_LABEL => {
Document::from_pkcs1_der(document.as_bytes())
- .map_err(|_| type_error("invalid PKCS#1 public key"))?
+ .map_err(|_| AsymmetricPublicKeyError::InvalidPkcs1PublicKey)?
}
EncryptedPrivateKeyInfo::PEM_LABEL
| PrivateKeyInfo::PEM_LABEL
@@ -754,27 +910,36 @@ impl KeyObjectHandle {
}
"CERTIFICATE" => {
let (_, pem) = x509_parser::pem::parse_x509_pem(pem.as_bytes())
- .map_err(|_| type_error("invalid x509 certificate"))?;
+ .map_err(|_| AsymmetricPublicKeyError::InvalidX509Certificate)?;
let cert = pem.parse_x509()?;
let public_key = cert.tbs_certificate.subject_pki;
- return KeyObjectHandle::new_x509_public_key(&public_key);
+ return KeyObjectHandle::new_x509_public_key(&public_key)
+ .map_err(Into::into);
}
_ => {
- return Err(type_error(format!("unsupported PEM label: {}", label)))
+ return Err(AsymmetricPublicKeyError::UnsupportedPemLabel(
+ label.to_string(),
+ ))
}
}
}
"der" => match typ {
"pkcs1" => Document::from_pkcs1_der(key)
- .map_err(|_| type_error("invalid PKCS#1 public key"))?,
+ .map_err(|_| AsymmetricPublicKeyError::InvalidPkcs1PublicKey)?,
"spki" => Document::from_public_key_der(key)
- .map_err(|_| type_error("invalid SPKI public key"))?,
- _ => return Err(type_error(format!("unsupported key type: {}", typ))),
+ .map_err(|_| AsymmetricPublicKeyError::InvalidSpkiPublicKey)?,
+ _ => {
+ return Err(AsymmetricPublicKeyError::UnsupportedKeyType(
+ typ.to_string(),
+ ))
+ }
},
_ => {
- return Err(type_error(format!("unsupported key format: {}", format)))
+ return Err(AsymmetricPublicKeyError::UnsupportedKeyType(
+ format.to_string(),
+ ))
}
};
@@ -799,16 +964,16 @@ impl KeyObjectHandle {
}
DSA_OID => {
let verifying_key = dsa::VerifyingKey::try_from(spki)
- .map_err(|_| type_error("malformed DSS public key"))?;
+ .map_err(|_| AsymmetricPublicKeyError::MalformedDssPublicKey)?;
AsymmetricPublicKey::Dsa(verifying_key)
}
EC_OID => {
let named_curve = spki.algorithm.parameters_oid().map_err(|_| {
- type_error("malformed or missing named curve in ec parameters")
- })?;
- let data = spki.subject_public_key.as_bytes().ok_or_else(|| {
- type_error("malformed or missing public key in ec spki")
+ AsymmetricPublicKeyError::MalformedOrMissingNamedCurveInEcParameters
})?;
+ let data = spki.subject_public_key.as_bytes().ok_or(
+ AsymmetricPublicKeyError::MalformedOrMissingPublicKeyInEcSpki,
+ )?;
match named_curve {
ID_SECP224R1_OID => {
@@ -823,54 +988,68 @@ impl KeyObjectHandle {
let public_key = p384::PublicKey::from_sec1_bytes(data)?;
AsymmetricPublicKey::Ec(EcPublicKey::P384(public_key))
}
- _ => return Err(type_error("unsupported ec named curve")),
+ _ => return Err(AsymmetricPublicKeyError::UnsupportedEcNamedCurve),
}
}
X25519_OID => {
let mut bytes = [0; 32];
- let data = spki.subject_public_key.as_bytes().ok_or_else(|| {
- type_error("malformed or missing public key in x25519 spki")
- })?;
+ let data = spki.subject_public_key.as_bytes().ok_or(
+ AsymmetricPublicKeyError::MalformedOrMissingPublicKeyInX25519Spki,
+ )?;
if data.len() < 32 {
- return Err(type_error("x25519 public key is too short"));
+ return Err(AsymmetricPublicKeyError::X25519PublicKeyIsTooShort);
}
bytes.copy_from_slice(&data[0..32]);
AsymmetricPublicKey::X25519(x25519_dalek::PublicKey::from(bytes))
}
ED25519_OID => {
let verifying_key = ed25519_dalek::VerifyingKey::try_from(spki)
- .map_err(|_| type_error("invalid Ed25519 private key"))?;
+ .map_err(|_| AsymmetricPublicKeyError::InvalidEd25519PublicKey)?;
AsymmetricPublicKey::Ed25519(verifying_key)
}
DH_KEY_AGREEMENT_OID => {
let params = spki
.algorithm
.parameters
- .ok_or_else(|| type_error("missing dh parameters"))?;
+ .ok_or(AsymmetricPublicKeyError::MissingDhParameters)?;
let params = pkcs3::DhParameter::from_der(&params.to_der().unwrap())
- .map_err(|_| type_error("malformed dh parameters"))?;
+ .map_err(|_| AsymmetricPublicKeyError::MalformedDhParameters)?;
let Some(subject_public_key) = spki.subject_public_key.as_bytes()
else {
- return Err(type_error("malformed or missing public key in dh spki"));
+ return Err(
+ AsymmetricPublicKeyError::MalformedOrMissingPublicKeyInDhSpki,
+ );
};
AsymmetricPublicKey::Dh(DhPublicKey {
key: dh::PublicKey::from_bytes(subject_public_key),
params,
})
}
- _ => return Err(type_error("unsupported public key oid")),
+ _ => return Err(AsymmetricPublicKeyError::UnsupportedPrivateKeyOid),
};
Ok(KeyObjectHandle::AsymmetricPublic(public_key))
}
}
+#[derive(Debug, thiserror::Error)]
+pub enum RsaPssParamsParseError {
+ #[error("malformed pss private key parameters")]
+ MalformedPssPrivateKeyParameters,
+ #[error("unsupported pss hash algorithm")]
+ UnsupportedPssHashAlgorithm,
+ #[error("unsupported pss mask gen algorithm")]
+ UnsupportedPssMaskGenAlgorithm,
+ #[error("malformed or missing pss mask gen algorithm parameters")]
+ MalformedOrMissingPssMaskGenAlgorithm,
+}
+
fn parse_rsa_pss_params(
parameters: Option<AnyRef<'_>>,
-) -> Result<Option<RsaPssDetails>, deno_core::anyhow::Error> {
+) -> Result<Option<RsaPssDetails>, RsaPssParamsParseError> {
let details = if let Some(parameters) = parameters {
let params = RsaPssParameters::try_from(parameters)
- .map_err(|_| type_error("malformed pss private key parameters"))?;
+ .map_err(|_| RsaPssParamsParseError::MalformedPssPrivateKeyParameters)?;
let hash_algorithm = match params.hash_algorithm.map(|k| k.oid) {
Some(ID_SHA1_OID) => RsaPssHashAlgorithm::Sha1,
@@ -881,16 +1060,16 @@ fn parse_rsa_pss_params(
Some(ID_SHA512_224_OID) => RsaPssHashAlgorithm::Sha512_224,
Some(ID_SHA512_256_OID) => RsaPssHashAlgorithm::Sha512_256,
None => RsaPssHashAlgorithm::Sha1,
- _ => return Err(type_error("unsupported pss hash algorithm")),
+ _ => return Err(RsaPssParamsParseError::UnsupportedPssHashAlgorithm),
};
let mf1_hash_algorithm = match params.mask_gen_algorithm {
Some(alg) => {
if alg.oid != ID_MFG1 {
- return Err(type_error("unsupported pss mask gen algorithm"));
+ return Err(RsaPssParamsParseError::UnsupportedPssMaskGenAlgorithm);
}
let params = alg.parameters_oid().map_err(|_| {
- type_error("malformed or missing pss mask gen algorithm parameters")
+ RsaPssParamsParseError::MalformedOrMissingPssMaskGenAlgorithm
})?;
match params {
ID_SHA1_OID => RsaPssHashAlgorithm::Sha1,
@@ -900,7 +1079,9 @@ fn parse_rsa_pss_params(
ID_SHA512_OID => RsaPssHashAlgorithm::Sha512,
ID_SHA512_224_OID => RsaPssHashAlgorithm::Sha512_224,
ID_SHA512_256_OID => RsaPssHashAlgorithm::Sha512_256,
- _ => return Err(type_error("unsupported pss mask gen algorithm")),
+ _ => {
+ return Err(RsaPssParamsParseError::UnsupportedPssMaskGenAlgorithm)
+ }
}
}
None => hash_algorithm,
@@ -921,14 +1102,49 @@ fn parse_rsa_pss_params(
Ok(details)
}
-use base64::prelude::BASE64_URL_SAFE_NO_PAD;
-
fn bytes_to_b64(bytes: &[u8]) -> String {
+ use base64::prelude::BASE64_URL_SAFE_NO_PAD;
BASE64_URL_SAFE_NO_PAD.encode(bytes)
}
+#[derive(Debug, thiserror::Error)]
+pub enum AsymmetricPublicKeyJwkError {
+ #[error("key is not an asymmetric public key")]
+ KeyIsNotAsymmetricPublicKey,
+ #[error("Unsupported JWK EC curve: P224")]
+ UnsupportedJwkEcCurveP224,
+ #[error("jwk export not implemented for this key type")]
+ JwkExportNotImplementedForKeyType,
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum AsymmetricPublicKeyDerError {
+ #[error("key is not an asymmetric public key")]
+ KeyIsNotAsymmetricPublicKey,
+ #[error("invalid RSA public key")]
+ InvalidRsaPublicKey,
+ #[error("exporting non-RSA public key as PKCS#1 is not supported")]
+ ExportingNonRsaPublicKeyAsPkcs1Unsupported,
+ #[error("invalid EC public key")]
+ InvalidEcPublicKey,
+ #[error("exporting RSA-PSS public key as SPKI is not supported yet")]
+ ExportingNonRsaPssPublicKeyAsSpkiUnsupported,
+ #[error("invalid DSA public key")]
+ InvalidDsaPublicKey,
+ #[error("invalid X25519 public key")]
+ InvalidX25519PublicKey,
+ #[error("invalid Ed25519 public key")]
+ InvalidEd25519PublicKey,
+ #[error("invalid DH public key")]
+ InvalidDhPublicKey,
+ #[error("unsupported key type: {0}")]
+ UnsupportedKeyType(String),
+}
+
impl AsymmetricPublicKey {
- fn export_jwk(&self) -> Result<deno_core::serde_json::Value, AnyError> {
+ fn export_jwk(
+ &self,
+ ) -> Result<deno_core::serde_json::Value, AsymmetricPublicKeyJwkError> {
match self {
AsymmetricPublicKey::Ec(key) => {
let jwk = key.to_jwk()?;
@@ -974,40 +1190,39 @@ impl AsymmetricPublicKey {
});
Ok(jwk)
}
- _ => Err(type_error("jwk export not implemented for this key type")),
+ _ => Err(AsymmetricPublicKeyJwkError::JwkExportNotImplementedForKeyType),
}
}
- fn export_der(&self, typ: &str) -> Result<Box<[u8]>, AnyError> {
+ fn export_der(
+ &self,
+ typ: &str,
+ ) -> Result<Box<[u8]>, AsymmetricPublicKeyDerError> {
match typ {
"pkcs1" => match self {
AsymmetricPublicKey::Rsa(key) => {
let der = key
.to_pkcs1_der()
- .map_err(|_| type_error("invalid RSA public key"))?
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidRsaPublicKey)?
.into_vec()
.into_boxed_slice();
Ok(der)
}
- _ => Err(type_error(
- "exporting non-RSA public key as PKCS#1 is not supported",
- )),
+ _ => Err(AsymmetricPublicKeyDerError::ExportingNonRsaPublicKeyAsPkcs1Unsupported),
},
"spki" => {
let der = match self {
AsymmetricPublicKey::Rsa(key) => key
.to_public_key_der()
- .map_err(|_| type_error("invalid RSA public key"))?
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidRsaPublicKey)?
.into_vec()
.into_boxed_slice(),
AsymmetricPublicKey::RsaPss(_key) => {
- return Err(generic_error(
- "exporting RSA-PSS public key as SPKI is not supported yet",
- ))
+ return Err(AsymmetricPublicKeyDerError::ExportingNonRsaPssPublicKeyAsSpkiUnsupported)
}
AsymmetricPublicKey::Dsa(key) => key
.to_public_key_der()
- .map_err(|_| type_error("invalid DSA public key"))?
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidDsaPublicKey)?
.into_vec()
.into_boxed_slice(),
AsymmetricPublicKey::Ec(key) => {
@@ -1023,12 +1238,12 @@ impl AsymmetricPublicKey {
parameters: Some(asn1::AnyRef::from(&oid)),
},
subject_public_key: BitStringRef::from_bytes(&sec1)
- .map_err(|_| type_error("invalid EC public key"))?,
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidEcPublicKey)?,
};
spki
.to_der()
- .map_err(|_| type_error("invalid EC public key"))?
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidEcPublicKey)?
.into_boxed_slice()
}
AsymmetricPublicKey::X25519(key) => {
@@ -1038,12 +1253,12 @@ impl AsymmetricPublicKey {
parameters: None,
},
subject_public_key: BitStringRef::from_bytes(key.as_bytes())
- .map_err(|_| type_error("invalid X25519 public key"))?,
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidX25519PublicKey)?,
};
spki
.to_der()
- .map_err(|_| type_error("invalid X25519 public key"))?
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidX25519PublicKey)?
.into_boxed_slice()
}
AsymmetricPublicKey::Ed25519(key) => {
@@ -1053,12 +1268,12 @@ impl AsymmetricPublicKey {
parameters: None,
},
subject_public_key: BitStringRef::from_bytes(key.as_bytes())
- .map_err(|_| type_error("invalid Ed25519 public key"))?,
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidEd25519PublicKey)?,
};
spki
.to_der()
- .map_err(|_| type_error("invalid Ed25519 public key"))?
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidEd25519PublicKey)?
.into_boxed_slice()
}
AsymmetricPublicKey::Dh(key) => {
@@ -1071,43 +1286,67 @@ impl AsymmetricPublicKey {
},
subject_public_key: BitStringRef::from_bytes(&public_key_bytes)
.map_err(|_| {
- type_error("invalid DH public key")
+ AsymmetricPublicKeyDerError::InvalidDhPublicKey
})?,
};
spki
.to_der()
- .map_err(|_| type_error("invalid DH public key"))?
+ .map_err(|_| AsymmetricPublicKeyDerError::InvalidDhPublicKey)?
.into_boxed_slice()
}
};
Ok(der)
}
- _ => Err(type_error(format!("unsupported key type: {}", typ))),
+ _ => Err(AsymmetricPublicKeyDerError::UnsupportedKeyType(typ.to_string())),
}
}
}
+#[derive(Debug, thiserror::Error)]
+pub enum AsymmetricPrivateKeyDerError {
+ #[error("key is not an asymmetric private key")]
+ KeyIsNotAsymmetricPrivateKey,
+ #[error("invalid RSA private key")]
+ InvalidRsaPrivateKey,
+ #[error("exporting non-RSA private key as PKCS#1 is not supported")]
+ ExportingNonRsaPrivateKeyAsPkcs1Unsupported,
+ #[error("invalid EC private key")]
+ InvalidEcPrivateKey,
+ #[error("exporting non-EC private key as SEC1 is not supported")]
+ ExportingNonEcPrivateKeyAsSec1Unsupported,
+ #[error("exporting RSA-PSS private key as PKCS#8 is not supported yet")]
+ ExportingNonRsaPssPrivateKeyAsPkcs8Unsupported,
+ #[error("invalid DSA private key")]
+ InvalidDsaPrivateKey,
+ #[error("invalid X25519 private key")]
+ InvalidX25519PrivateKey,
+ #[error("invalid Ed25519 private key")]
+ InvalidEd25519PrivateKey,
+ #[error("invalid DH private key")]
+ InvalidDhPrivateKey,
+ #[error("unsupported key type: {0}")]
+ UnsupportedKeyType(String),
+}
+
impl AsymmetricPrivateKey {
fn export_der(
&self,
typ: &str,
// cipher: Option<&str>,
// passphrase: Option<&str>,
- ) -> Result<Box<[u8]>, AnyError> {
+ ) -> Result<Box<[u8]>, AsymmetricPrivateKeyDerError> {
match typ {
"pkcs1" => match self {
AsymmetricPrivateKey::Rsa(key) => {
let der = key
.to_pkcs1_der()
- .map_err(|_| type_error("invalid RSA private key"))?
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidRsaPrivateKey)?
.to_bytes()
.to_vec()
.into_boxed_slice();
Ok(der)
}
- _ => Err(type_error(
- "exporting non-RSA private key as PKCS#1 is not supported",
- )),
+ _ => Err(AsymmetricPrivateKeyDerError::ExportingNonRsaPrivateKeyAsPkcs1Unsupported),
},
"sec1" => match self {
AsymmetricPrivateKey::Ec(key) => {
@@ -1116,30 +1355,26 @@ impl AsymmetricPrivateKey {
EcPrivateKey::P256(key) => key.to_sec1_der(),
EcPrivateKey::P384(key) => key.to_sec1_der(),
}
- .map_err(|_| type_error("invalid EC private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidEcPrivateKey)?;
Ok(sec1.to_vec().into_boxed_slice())
}
- _ => Err(type_error(
- "exporting non-EC private key as SEC1 is not supported",
- )),
+ _ => Err(AsymmetricPrivateKeyDerError::ExportingNonEcPrivateKeyAsSec1Unsupported),
},
"pkcs8" => {
let der = match self {
AsymmetricPrivateKey::Rsa(key) => {
let document = key
.to_pkcs8_der()
- .map_err(|_| type_error("invalid RSA private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidRsaPrivateKey)?;
document.to_bytes().to_vec().into_boxed_slice()
}
AsymmetricPrivateKey::RsaPss(_key) => {
- return Err(generic_error(
- "exporting RSA-PSS private key as PKCS#8 is not supported yet",
- ))
+ return Err(AsymmetricPrivateKeyDerError::ExportingNonRsaPssPrivateKeyAsPkcs8Unsupported)
}
AsymmetricPrivateKey::Dsa(key) => {
let document = key
.to_pkcs8_der()
- .map_err(|_| type_error("invalid DSA private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidDsaPrivateKey)?;
document.to_bytes().to_vec().into_boxed_slice()
}
AsymmetricPrivateKey::Ec(key) => {
@@ -1148,14 +1383,14 @@ impl AsymmetricPrivateKey {
EcPrivateKey::P256(key) => key.to_pkcs8_der(),
EcPrivateKey::P384(key) => key.to_pkcs8_der(),
}
- .map_err(|_| type_error("invalid EC private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidEcPrivateKey)?;
document.to_bytes().to_vec().into_boxed_slice()
}
AsymmetricPrivateKey::X25519(key) => {
let private_key = OctetStringRef::new(key.as_bytes())
- .map_err(|_| type_error("invalid X25519 private key"))?
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidX25519PrivateKey)?
.to_der()
- .map_err(|_| type_error("invalid X25519 private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidX25519PrivateKey)?;
let private_key = PrivateKeyInfo {
algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
@@ -1168,15 +1403,15 @@ impl AsymmetricPrivateKey {
let der = private_key
.to_der()
- .map_err(|_| type_error("invalid X25519 private key"))?
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidX25519PrivateKey)?
.into_boxed_slice();
return Ok(der);
}
AsymmetricPrivateKey::Ed25519(key) => {
let private_key = OctetStringRef::new(key.as_bytes())
- .map_err(|_| type_error("invalid Ed25519 private key"))?
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidEd25519PrivateKey)?
.to_der()
- .map_err(|_| type_error("invalid Ed25519 private key"))?;
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidEd25519PrivateKey)?;
let private_key = PrivateKeyInfo {
algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
@@ -1189,7 +1424,7 @@ impl AsymmetricPrivateKey {
private_key
.to_der()
- .map_err(|_| type_error("invalid ED25519 private key"))?
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidEd25519PrivateKey)?
.into_boxed_slice()
}
AsymmetricPrivateKey::Dh(key) => {
@@ -1206,14 +1441,14 @@ impl AsymmetricPrivateKey {
private_key
.to_der()
- .map_err(|_| type_error("invalid DH private key"))?
+ .map_err(|_| AsymmetricPrivateKeyDerError::InvalidDhPrivateKey)?
.into_boxed_slice()
}
};
Ok(der)
}
- _ => Err(type_error(format!("unsupported key type: {}", typ))),
+ _ => Err(AsymmetricPrivateKeyDerError::UnsupportedKeyType(typ.to_string())),
}
}
}
@@ -1225,7 +1460,7 @@ pub fn op_node_create_private_key(
#[string] format: &str,
#[string] typ: &str,
#[buffer] passphrase: Option<&[u8]>,
-) -> Result<KeyObjectHandle, AnyError> {
+) -> Result<KeyObjectHandle, AsymmetricPrivateKeyError> {
KeyObjectHandle::new_asymmetric_private_key_from_js(
key, format, typ, passphrase,
)
@@ -1237,7 +1472,7 @@ pub fn op_node_create_ed_raw(
#[string] curve: &str,
#[buffer] key: &[u8],
is_public: bool,
-) -> Result<KeyObjectHandle, AnyError> {
+) -> Result<KeyObjectHandle, EdRawError> {
KeyObjectHandle::new_ed_raw(curve, key, is_public)
}
@@ -1255,16 +1490,16 @@ pub struct RsaJwkKey {
pub fn op_node_create_rsa_jwk(
#[serde] jwk: RsaJwkKey,
is_public: bool,
-) -> Result<KeyObjectHandle, AnyError> {
+) -> Result<KeyObjectHandle, RsaJwkError> {
KeyObjectHandle::new_rsa_jwk(jwk, is_public)
}
#[op2]
#[cppgc]
pub fn op_node_create_ec_jwk(
- #[serde] jwk: elliptic_curve::JwkEcKey,
+ #[serde] jwk: JwkEcKey,
is_public: bool,
-) -> Result<KeyObjectHandle, AnyError> {
+) -> Result<KeyObjectHandle, EcJwkError> {
KeyObjectHandle::new_ec_jwk(&jwk, is_public)
}
@@ -1275,7 +1510,7 @@ pub fn op_node_create_public_key(
#[string] format: &str,
#[string] typ: &str,
#[buffer] passphrase: Option<&[u8]>,
-) -> Result<KeyObjectHandle, AnyError> {
+) -> Result<KeyObjectHandle, AsymmetricPublicKeyError> {
KeyObjectHandle::new_asymmetric_public_key_from_js(
key, format, typ, passphrase,
)
@@ -1293,7 +1528,7 @@ pub fn op_node_create_secret_key(
#[string]
pub fn op_node_get_asymmetric_key_type(
#[cppgc] handle: &KeyObjectHandle,
-) -> Result<&'static str, AnyError> {
+) -> Result<&'static str, deno_core::error::AnyError> {
match handle {
KeyObjectHandle::AsymmetricPrivate(AsymmetricPrivateKey::Rsa(_))
| KeyObjectHandle::AsymmetricPublic(AsymmetricPublicKey::Rsa(_)) => {
@@ -1364,7 +1599,7 @@ pub enum AsymmetricKeyDetails {
#[serde]
pub fn op_node_get_asymmetric_key_details(
#[cppgc] handle: &KeyObjectHandle,
-) -> Result<AsymmetricKeyDetails, AnyError> {
+) -> Result<AsymmetricKeyDetails, deno_core::error::AnyError> {
match handle {
KeyObjectHandle::AsymmetricPrivate(private_key) => match private_key {
AsymmetricPrivateKey::Rsa(key) => {
@@ -1482,12 +1717,10 @@ pub fn op_node_get_asymmetric_key_details(
#[smi]
pub fn op_node_get_symmetric_key_size(
#[cppgc] handle: &KeyObjectHandle,
-) -> Result<usize, AnyError> {
+) -> Result<usize, deno_core::error::AnyError> {
match handle {
- KeyObjectHandle::AsymmetricPrivate(_) => {
- Err(type_error("asymmetric key is not a symmetric key"))
- }
- KeyObjectHandle::AsymmetricPublic(_) => {
+ KeyObjectHandle::AsymmetricPrivate(_)
+ | KeyObjectHandle::AsymmetricPublic(_) => {
Err(type_error("asymmetric key is not a symmetric key"))
}
KeyObjectHandle::Secret(key) => Ok(key.len() * 8),
@@ -1592,13 +1825,17 @@ pub async fn op_node_generate_rsa_key_async(
.unwrap()
}
+#[derive(Debug, thiserror::Error)]
+#[error("digest not allowed for RSA-PSS keys{}", .0.as_ref().map(|digest| format!(": {digest}")).unwrap_or_default())]
+pub struct GenerateRsaPssError(Option<String>);
+
fn generate_rsa_pss(
modulus_length: usize,
public_exponent: usize,
hash_algorithm: Option<&str>,
mf1_hash_algorithm: Option<&str>,
salt_length: Option<u32>,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, GenerateRsaPssError> {
let key = RsaPrivateKey::new_with_exp(
&mut thread_rng(),
modulus_length,
@@ -1617,25 +1854,19 @@ fn generate_rsa_pss(
let hash_algorithm = match_fixed_digest_with_oid!(
hash_algorithm,
fn (algorithm: Option<RsaPssHashAlgorithm>) {
- algorithm.ok_or_else(|| type_error("digest not allowed for RSA-PSS keys: {}"))?
+ algorithm.ok_or(GenerateRsaPssError(None))?
},
_ => {
- return Err(type_error(format!(
- "digest not allowed for RSA-PSS keys: {}",
- hash_algorithm
- )))
+ return Err(GenerateRsaPssError(Some(hash_algorithm.to_string())))
}
);
let mf1_hash_algorithm = match_fixed_digest_with_oid!(
mf1_hash_algorithm,
fn (algorithm: Option<RsaPssHashAlgorithm>) {
- algorithm.ok_or_else(|| type_error("digest not allowed for RSA-PSS keys: {}"))?
+ algorithm.ok_or(GenerateRsaPssError(None))?
},
_ => {
- return Err(type_error(format!(
- "digest not allowed for RSA-PSS keys: {}",
- mf1_hash_algorithm
- )))
+ return Err(GenerateRsaPssError(Some(mf1_hash_algorithm.to_string())))
}
);
let salt_length =
@@ -1663,7 +1894,7 @@ pub fn op_node_generate_rsa_pss_key(
#[string] hash_algorithm: Option<String>, // todo: Option<&str> not supproted in ops yet
#[string] mf1_hash_algorithm: Option<String>, // todo: Option<&str> not supproted in ops yet
#[smi] salt_length: Option<u32>,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, GenerateRsaPssError> {
generate_rsa_pss(
modulus_length,
public_exponent,
@@ -1681,7 +1912,7 @@ pub async fn op_node_generate_rsa_pss_key_async(
#[string] hash_algorithm: Option<String>, // todo: Option<&str> not supproted in ops yet
#[string] mf1_hash_algorithm: Option<String>, // todo: Option<&str> not supproted in ops yet
#[smi] salt_length: Option<u32>,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, GenerateRsaPssError> {
spawn_blocking(move || {
generate_rsa_pss(
modulus_length,
@@ -1698,7 +1929,7 @@ pub async fn op_node_generate_rsa_pss_key_async(
fn dsa_generate(
modulus_length: usize,
divisor_length: usize,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, deno_core::error::AnyError> {
let mut rng = rand::thread_rng();
use dsa::Components;
use dsa::KeySize;
@@ -1729,7 +1960,7 @@ fn dsa_generate(
pub fn op_node_generate_dsa_key(
#[smi] modulus_length: usize,
#[smi] divisor_length: usize,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, deno_core::error::AnyError> {
dsa_generate(modulus_length, divisor_length)
}
@@ -1738,13 +1969,15 @@ pub fn op_node_generate_dsa_key(
pub async fn op_node_generate_dsa_key_async(
#[smi] modulus_length: usize,
#[smi] divisor_length: usize,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, deno_core::error::AnyError> {
spawn_blocking(move || dsa_generate(modulus_length, divisor_length))
.await
.unwrap()
}
-fn ec_generate(named_curve: &str) -> Result<KeyObjectHandlePair, AnyError> {
+fn ec_generate(
+ named_curve: &str,
+) -> Result<KeyObjectHandlePair, deno_core::error::AnyError> {
let mut rng = rand::thread_rng();
// TODO(@littledivy): Support public key point encoding.
// Default is uncompressed.
@@ -1776,7 +2009,7 @@ fn ec_generate(named_curve: &str) -> Result<KeyObjectHandlePair, AnyError> {
#[cppgc]
pub fn op_node_generate_ec_key(
#[string] named_curve: &str,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, deno_core::error::AnyError> {
ec_generate(named_curve)
}
@@ -1784,7 +2017,7 @@ pub fn op_node_generate_ec_key(
#[cppgc]
pub async fn op_node_generate_ec_key_async(
#[string] named_curve: String,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, deno_core::error::AnyError> {
spawn_blocking(move || ec_generate(&named_curve))
.await
.unwrap()
@@ -1840,7 +2073,7 @@ fn u32_slice_to_u8_slice(slice: &[u32]) -> &[u8] {
fn dh_group_generate(
group_name: &str,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, deno_core::error::AnyError> {
let (dh, prime, generator) = match group_name {
"modp5" => (
dh::DiffieHellman::group::<dh::Modp1536>(),
@@ -1895,7 +2128,7 @@ fn dh_group_generate(
#[cppgc]
pub fn op_node_generate_dh_group_key(
#[string] group_name: &str,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, deno_core::error::AnyError> {
dh_group_generate(group_name)
}
@@ -1903,7 +2136,7 @@ pub fn op_node_generate_dh_group_key(
#[cppgc]
pub async fn op_node_generate_dh_group_key_async(
#[string] group_name: String,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> Result<KeyObjectHandlePair, deno_core::error::AnyError> {
spawn_blocking(move || dh_group_generate(&group_name))
.await
.unwrap()
@@ -1913,7 +2146,7 @@ fn dh_generate(
prime: Option<&[u8]>,
prime_len: usize,
generator: usize,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> KeyObjectHandlePair {
let prime = prime
.map(|p| p.into())
.unwrap_or_else(|| Prime::generate(prime_len));
@@ -1923,7 +2156,7 @@ fn dh_generate(
base: asn1::Int::new(generator.to_be_bytes().as_slice()).unwrap(),
private_value_length: None,
};
- Ok(KeyObjectHandlePair::new(
+ KeyObjectHandlePair::new(
AsymmetricPrivateKey::Dh(DhPrivateKey {
key: dh.private_key,
params: params.clone(),
@@ -1932,7 +2165,7 @@ fn dh_generate(
key: dh.public_key,
params,
}),
- ))
+ )
}
#[op2]
@@ -1941,7 +2174,7 @@ pub fn op_node_generate_dh_key(
#[buffer] prime: Option<&[u8]>,
#[smi] prime_len: usize,
#[smi] generator: usize,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> KeyObjectHandlePair {
dh_generate(prime, prime_len, generator)
}
@@ -1951,7 +2184,7 @@ pub async fn op_node_generate_dh_key_async(
#[buffer(copy)] prime: Option<Box<[u8]>>,
#[smi] prime_len: usize,
#[smi] generator: usize,
-) -> Result<KeyObjectHandlePair, AnyError> {
+) -> KeyObjectHandlePair {
spawn_blocking(move || dh_generate(prime.as_deref(), prime_len, generator))
.await
.unwrap()
@@ -1963,21 +2196,21 @@ pub fn op_node_dh_keys_generate_and_export(
#[buffer] prime: Option<&[u8]>,
#[smi] prime_len: usize,
#[smi] generator: usize,
-) -> Result<(ToJsBuffer, ToJsBuffer), AnyError> {
+) -> (ToJsBuffer, ToJsBuffer) {
let prime = prime
.map(|p| p.into())
.unwrap_or_else(|| Prime::generate(prime_len));
let dh = dh::DiffieHellman::new(prime, generator);
let private_key = dh.private_key.into_vec().into_boxed_slice();
let public_key = dh.public_key.into_vec().into_boxed_slice();
- Ok((private_key.into(), public_key.into()))
+ (private_key.into(), public_key.into())
}
#[op2]
#[buffer]
pub fn op_node_export_secret_key(
#[cppgc] handle: &KeyObjectHandle,
-) -> Result<Box<[u8]>, AnyError> {
+) -> Result<Box<[u8]>, deno_core::error::AnyError> {
let key = handle
.as_secret_key()
.ok_or_else(|| type_error("key is not a secret key"))?;
@@ -1988,7 +2221,7 @@ pub fn op_node_export_secret_key(
#[string]
pub fn op_node_export_secret_key_b64url(
#[cppgc] handle: &KeyObjectHandle,
-) -> Result<String, AnyError> {
+) -> Result<String, deno_core::error::AnyError> {
let key = handle
.as_secret_key()
.ok_or_else(|| type_error("key is not a secret key"))?;
@@ -1999,23 +2232,33 @@ pub fn op_node_export_secret_key_b64url(
#[serde]
pub fn op_node_export_public_key_jwk(
#[cppgc] handle: &KeyObjectHandle,
-) -> Result<deno_core::serde_json::Value, AnyError> {
+) -> Result<deno_core::serde_json::Value, AsymmetricPublicKeyJwkError> {
let public_key = handle
.as_public_key()
- .ok_or_else(|| type_error("key is not an asymmetric public key"))?;
+ .ok_or(AsymmetricPublicKeyJwkError::KeyIsNotAsymmetricPublicKey)?;
public_key.export_jwk()
}
+#[derive(Debug, thiserror::Error)]
+pub enum ExportPublicKeyPemError {
+ #[error(transparent)]
+ AsymmetricPublicKeyDer(#[from] AsymmetricPublicKeyDerError),
+ #[error("very large data")]
+ VeryLargeData,
+ #[error(transparent)]
+ Der(#[from] der::Error),
+}
+
#[op2]
#[string]
pub fn op_node_export_public_key_pem(
#[cppgc] handle: &KeyObjectHandle,
#[string] typ: &str,
-) -> Result<String, AnyError> {
+) -> Result<String, ExportPublicKeyPemError> {
let public_key = handle
.as_public_key()
- .ok_or_else(|| type_error("key is not an asymmetric public key"))?;
+ .ok_or(AsymmetricPublicKeyDerError::KeyIsNotAsymmetricPublicKey)?;
let data = public_key.export_der(typ)?;
let label = match typ {
@@ -2025,7 +2268,7 @@ pub fn op_node_export_public_key_pem(
};
let pem_len = der::pem::encapsulated_len(label, LineEnding::LF, data.len())
- .map_err(|_| type_error("very large data"))?;
+ .map_err(|_| ExportPublicKeyPemError::VeryLargeData)?;
let mut out = vec![0; pem_len];
let mut writer = PemWriter::new(label, LineEnding::LF, &mut out)?;
writer.write(&data)?;
@@ -2040,22 +2283,32 @@ pub fn op_node_export_public_key_pem(
pub fn op_node_export_public_key_der(
#[cppgc] handle: &KeyObjectHandle,
#[string] typ: &str,
-) -> Result<Box<[u8]>, AnyError> {
+) -> Result<Box<[u8]>, AsymmetricPublicKeyDerError> {
let public_key = handle
.as_public_key()
- .ok_or_else(|| type_error("key is not an asymmetric public key"))?;
+ .ok_or(AsymmetricPublicKeyDerError::KeyIsNotAsymmetricPublicKey)?;
public_key.export_der(typ)
}
+#[derive(Debug, thiserror::Error)]
+pub enum ExportPrivateKeyPemError {
+ #[error(transparent)]
+ AsymmetricPublicKeyDer(#[from] AsymmetricPrivateKeyDerError),
+ #[error("very large data")]
+ VeryLargeData,
+ #[error(transparent)]
+ Der(#[from] der::Error),
+}
+
#[op2]
#[string]
pub fn op_node_export_private_key_pem(
#[cppgc] handle: &KeyObjectHandle,
#[string] typ: &str,
-) -> Result<String, AnyError> {
+) -> Result<String, ExportPrivateKeyPemError> {
let private_key = handle
.as_private_key()
- .ok_or_else(|| type_error("key is not an asymmetric private key"))?;
+ .ok_or(AsymmetricPrivateKeyDerError::KeyIsNotAsymmetricPrivateKey)?;
let data = private_key.export_der(typ)?;
let label = match typ {
@@ -2066,7 +2319,7 @@ pub fn op_node_export_private_key_pem(
};
let pem_len = der::pem::encapsulated_len(label, LineEnding::LF, data.len())
- .map_err(|_| type_error("very large data"))?;
+ .map_err(|_| ExportPrivateKeyPemError::VeryLargeData)?;
let mut out = vec![0; pem_len];
let mut writer = PemWriter::new(label, LineEnding::LF, &mut out)?;
writer.write(&data)?;
@@ -2081,10 +2334,10 @@ pub fn op_node_export_private_key_pem(
pub fn op_node_export_private_key_der(
#[cppgc] handle: &KeyObjectHandle,
#[string] typ: &str,
-) -> Result<Box<[u8]>, AnyError> {
+) -> Result<Box<[u8]>, AsymmetricPrivateKeyDerError> {
let private_key = handle
.as_private_key()
- .ok_or_else(|| type_error("key is not an asymmetric private key"))?;
+ .ok_or(AsymmetricPrivateKeyDerError::KeyIsNotAsymmetricPrivateKey)?;
private_key.export_der(typ)
}
@@ -2102,7 +2355,7 @@ pub fn op_node_key_type(#[cppgc] handle: &KeyObjectHandle) -> &'static str {
#[cppgc]
pub fn op_node_derive_public_key_from_private_key(
#[cppgc] handle: &KeyObjectHandle,
-) -> Result<KeyObjectHandle, AnyError> {
+) -> Result<KeyObjectHandle, deno_core::error::AnyError> {
let Some(private_key) = handle.as_private_key() else {
return Err(type_error("expected private key"));
};
diff --git a/ext/node/ops/crypto/mod.rs b/ext/node/ops/crypto/mod.rs
index 0cf34511b..e90e82090 100644
--- a/ext/node/ops/crypto/mod.rs
+++ b/ext/node/ops/crypto/mod.rs
@@ -1,7 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::generic_error;
use deno_core::error::type_error;
-use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::unsync::spawn_blocking;
use deno_core::JsBuffer;
@@ -34,14 +33,14 @@ use rsa::Pkcs1v15Encrypt;
use rsa::RsaPrivateKey;
use rsa::RsaPublicKey;
-mod cipher;
+pub mod cipher;
mod dh;
-mod digest;
+pub mod digest;
pub mod keys;
mod md5_sha1;
mod pkcs3;
mod primes;
-mod sign;
+pub mod sign;
pub mod x509;
use self::digest::match_fixed_digest_with_eager_block_buffer;
@@ -58,38 +57,31 @@ pub fn op_node_check_prime(
pub fn op_node_check_prime_bytes(
#[anybuffer] bytes: &[u8],
#[number] checks: usize,
-) -> Result<bool, AnyError> {
+) -> bool {
let candidate = BigInt::from_bytes_be(num_bigint::Sign::Plus, bytes);
- Ok(primes::is_probably_prime(&candidate, checks))
+ primes::is_probably_prime(&candidate, checks)
}
#[op2(async)]
pub async fn op_node_check_prime_async(
#[bigint] num: i64,
#[number] checks: usize,
-) -> Result<bool, AnyError> {
+) -> Result<bool, tokio::task::JoinError> {
// TODO(@littledivy): use rayon for CPU-bound tasks
- Ok(
- spawn_blocking(move || {
- primes::is_probably_prime(&BigInt::from(num), checks)
- })
- .await?,
- )
+ spawn_blocking(move || primes::is_probably_prime(&BigInt::from(num), checks))
+ .await
}
#[op2(async)]
pub fn op_node_check_prime_bytes_async(
#[anybuffer] bytes: &[u8],
#[number] checks: usize,
-) -> Result<impl Future<Output = Result<bool, AnyError>>, AnyError> {
+) -> impl Future<Output = Result<bool, tokio::task::JoinError>> {
let candidate = BigInt::from_bytes_be(num_bigint::Sign::Plus, bytes);
// TODO(@littledivy): use rayon for CPU-bound tasks
- Ok(async move {
- Ok(
- spawn_blocking(move || primes::is_probably_prime(&candidate, checks))
- .await?,
- )
- })
+ async move {
+ spawn_blocking(move || primes::is_probably_prime(&candidate, checks)).await
+ }
}
#[op2]
@@ -97,7 +89,7 @@ pub fn op_node_check_prime_bytes_async(
pub fn op_node_create_hash(
#[string] algorithm: &str,
output_length: Option<u32>,
-) -> Result<digest::Hasher, AnyError> {
+) -> Result<digest::Hasher, digest::HashError> {
digest::Hasher::new(algorithm, output_length.map(|l| l as usize))
}
@@ -145,17 +137,31 @@ pub fn op_node_hash_digest_hex(
pub fn op_node_hash_clone(
#[cppgc] hasher: &digest::Hasher,
output_length: Option<u32>,
-) -> Result<Option<digest::Hasher>, AnyError> {
+) -> Result<Option<digest::Hasher>, digest::HashError> {
hasher.clone_inner(output_length.map(|l| l as usize))
}
+#[derive(Debug, thiserror::Error)]
+pub enum PrivateEncryptDecryptError {
+ #[error(transparent)]
+ Pkcs8(#[from] pkcs8::Error),
+ #[error(transparent)]
+ Spki(#[from] spki::Error),
+ #[error(transparent)]
+ Utf8(#[from] std::str::Utf8Error),
+ #[error(transparent)]
+ Rsa(#[from] rsa::Error),
+ #[error("Unknown padding")]
+ UnknownPadding,
+}
+
#[op2]
#[serde]
pub fn op_node_private_encrypt(
#[serde] key: StringOrBuffer,
#[serde] msg: StringOrBuffer,
#[smi] padding: u32,
-) -> Result<ToJsBuffer, AnyError> {
+) -> Result<ToJsBuffer, PrivateEncryptDecryptError> {
let key = RsaPrivateKey::from_pkcs8_pem((&key).try_into()?)?;
let mut rng = rand::thread_rng();
@@ -172,7 +178,7 @@ pub fn op_node_private_encrypt(
.encrypt(&mut rng, Oaep::new::<sha1::Sha1>(), &msg)?
.into(),
),
- _ => Err(type_error("Unknown padding")),
+ _ => Err(PrivateEncryptDecryptError::UnknownPadding),
}
}
@@ -182,13 +188,13 @@ pub fn op_node_private_decrypt(
#[serde] key: StringOrBuffer,
#[serde] msg: StringOrBuffer,
#[smi] padding: u32,
-) -> Result<ToJsBuffer, AnyError> {
+) -> Result<ToJsBuffer, PrivateEncryptDecryptError> {
let key = RsaPrivateKey::from_pkcs8_pem((&key).try_into()?)?;
match padding {
1 => Ok(key.decrypt(Pkcs1v15Encrypt, &msg)?.into()),
4 => Ok(key.decrypt(Oaep::new::<sha1::Sha1>(), &msg)?.into()),
- _ => Err(type_error("Unknown padding")),
+ _ => Err(PrivateEncryptDecryptError::UnknownPadding),
}
}
@@ -198,7 +204,7 @@ pub fn op_node_public_encrypt(
#[serde] key: StringOrBuffer,
#[serde] msg: StringOrBuffer,
#[smi] padding: u32,
-) -> Result<ToJsBuffer, AnyError> {
+) -> Result<ToJsBuffer, PrivateEncryptDecryptError> {
let key = RsaPublicKey::from_public_key_pem((&key).try_into()?)?;
let mut rng = rand::thread_rng();
@@ -209,7 +215,7 @@ pub fn op_node_public_encrypt(
.encrypt(&mut rng, Oaep::new::<sha1::Sha1>(), &msg)?
.into(),
),
- _ => Err(type_error("Unknown padding")),
+ _ => Err(PrivateEncryptDecryptError::UnknownPadding),
}
}
@@ -220,7 +226,7 @@ pub fn op_node_create_cipheriv(
#[string] algorithm: &str,
#[buffer] key: &[u8],
#[buffer] iv: &[u8],
-) -> Result<u32, AnyError> {
+) -> Result<u32, cipher::CipherContextError> {
let context = cipher::CipherContext::new(algorithm, key, iv)?;
Ok(state.resource_table.add(context))
}
@@ -262,11 +268,14 @@ pub fn op_node_cipheriv_final(
auto_pad: bool,
#[buffer] input: &[u8],
#[anybuffer] output: &mut [u8],
-) -> Result<Option<Vec<u8>>, AnyError> {
- let context = state.resource_table.take::<cipher::CipherContext>(rid)?;
+) -> Result<Option<Vec<u8>>, cipher::CipherContextError> {
+ let context = state
+ .resource_table
+ .take::<cipher::CipherContext>(rid)
+ .map_err(cipher::CipherContextError::Resource)?;
let context = Rc::try_unwrap(context)
- .map_err(|_| type_error("Cipher context is already in use"))?;
- context.r#final(auto_pad, input, output)
+ .map_err(|_| cipher::CipherContextError::ContextInUse)?;
+ context.r#final(auto_pad, input, output).map_err(Into::into)
}
#[op2]
@@ -274,10 +283,13 @@ pub fn op_node_cipheriv_final(
pub fn op_node_cipheriv_take(
state: &mut OpState,
#[smi] rid: u32,
-) -> Result<Option<Vec<u8>>, AnyError> {
- let context = state.resource_table.take::<cipher::CipherContext>(rid)?;
+) -> Result<Option<Vec<u8>>, cipher::CipherContextError> {
+ let context = state
+ .resource_table
+ .take::<cipher::CipherContext>(rid)
+ .map_err(cipher::CipherContextError::Resource)?;
let context = Rc::try_unwrap(context)
- .map_err(|_| type_error("Cipher context is already in use"))?;
+ .map_err(|_| cipher::CipherContextError::ContextInUse)?;
Ok(context.take_tag())
}
@@ -288,7 +300,7 @@ pub fn op_node_create_decipheriv(
#[string] algorithm: &str,
#[buffer] key: &[u8],
#[buffer] iv: &[u8],
-) -> Result<u32, AnyError> {
+) -> Result<u32, cipher::DecipherContextError> {
let context = cipher::DecipherContext::new(algorithm, key, iv)?;
Ok(state.resource_table.add(context))
}
@@ -326,10 +338,13 @@ pub fn op_node_decipheriv_decrypt(
pub fn op_node_decipheriv_take(
state: &mut OpState,
#[smi] rid: u32,
-) -> Result<(), AnyError> {
- let context = state.resource_table.take::<cipher::DecipherContext>(rid)?;
+) -> Result<(), cipher::DecipherContextError> {
+ let context = state
+ .resource_table
+ .take::<cipher::DecipherContext>(rid)
+ .map_err(cipher::DecipherContextError::Resource)?;
Rc::try_unwrap(context)
- .map_err(|_| type_error("Cipher context is already in use"))?;
+ .map_err(|_| cipher::DecipherContextError::ContextInUse)?;
Ok(())
}
@@ -341,11 +356,16 @@ pub fn op_node_decipheriv_final(
#[buffer] input: &[u8],
#[anybuffer] output: &mut [u8],
#[buffer] auth_tag: &[u8],
-) -> Result<(), AnyError> {
- let context = state.resource_table.take::<cipher::DecipherContext>(rid)?;
+) -> Result<(), cipher::DecipherContextError> {
+ let context = state
+ .resource_table
+ .take::<cipher::DecipherContext>(rid)
+ .map_err(cipher::DecipherContextError::Resource)?;
let context = Rc::try_unwrap(context)
- .map_err(|_| type_error("Cipher context is already in use"))?;
- context.r#final(auto_pad, input, output, auth_tag)
+ .map_err(|_| cipher::DecipherContextError::ContextInUse)?;
+ context
+ .r#final(auto_pad, input, output, auth_tag)
+ .map_err(Into::into)
}
#[op2]
@@ -356,7 +376,7 @@ pub fn op_node_sign(
#[string] digest_type: &str,
#[smi] pss_salt_length: Option<u32>,
#[smi] dsa_signature_encoding: u32,
-) -> Result<Box<[u8]>, AnyError> {
+) -> Result<Box<[u8]>, sign::KeyObjectHandlePrehashedSignAndVerifyError> {
handle.sign_prehashed(
digest_type,
digest,
@@ -373,7 +393,7 @@ pub fn op_node_verify(
#[buffer] signature: &[u8],
#[smi] pss_salt_length: Option<u32>,
#[smi] dsa_signature_encoding: u32,
-) -> Result<bool, AnyError> {
+) -> Result<bool, sign::KeyObjectHandlePrehashedSignAndVerifyError> {
handle.verify_prehashed(
digest_type,
digest,
@@ -383,13 +403,21 @@ pub fn op_node_verify(
)
}
+#[derive(Debug, thiserror::Error)]
+pub enum Pbkdf2Error {
+ #[error("unsupported digest: {0}")]
+ UnsupportedDigest(String),
+ #[error(transparent)]
+ Join(#[from] tokio::task::JoinError),
+}
+
fn pbkdf2_sync(
password: &[u8],
salt: &[u8],
iterations: u32,
algorithm_name: &str,
derived_key: &mut [u8],
-) -> Result<(), AnyError> {
+) -> Result<(), Pbkdf2Error> {
match_fixed_digest_with_eager_block_buffer!(
algorithm_name,
fn <D>() {
@@ -397,10 +425,7 @@ fn pbkdf2_sync(
Ok(())
},
_ => {
- Err(type_error(format!(
- "unsupported digest: {}",
- algorithm_name
- )))
+ Err(Pbkdf2Error::UnsupportedDigest(algorithm_name.to_string()))
}
)
}
@@ -424,7 +449,7 @@ pub async fn op_node_pbkdf2_async(
#[smi] iterations: u32,
#[string] digest: String,
#[number] keylen: usize,
-) -> Result<ToJsBuffer, AnyError> {
+) -> Result<ToJsBuffer, Pbkdf2Error> {
spawn_blocking(move || {
let mut derived_key = vec![0; keylen];
pbkdf2_sync(&password, &salt, iterations, &digest, &mut derived_key)
@@ -450,15 +475,27 @@ pub async fn op_node_fill_random_async(#[smi] len: i32) -> ToJsBuffer {
.unwrap()
}
+#[derive(Debug, thiserror::Error)]
+pub enum HkdfError {
+ #[error("expected secret key")]
+ ExpectedSecretKey,
+ #[error("HKDF-Expand failed")]
+ HkdfExpandFailed,
+ #[error("Unsupported digest: {0}")]
+ UnsupportedDigest(String),
+ #[error(transparent)]
+ Join(#[from] tokio::task::JoinError),
+}
+
fn hkdf_sync(
digest_algorithm: &str,
handle: &KeyObjectHandle,
salt: &[u8],
info: &[u8],
okm: &mut [u8],
-) -> Result<(), AnyError> {
+) -> Result<(), HkdfError> {
let Some(ikm) = handle.as_secret_key() else {
- return Err(type_error("expected secret key"));
+ return Err(HkdfError::ExpectedSecretKey);
};
match_fixed_digest_with_eager_block_buffer!(
@@ -466,10 +503,10 @@ fn hkdf_sync(
fn <D>() {
let hk = Hkdf::<D>::new(Some(salt), ikm);
hk.expand(info, okm)
- .map_err(|_| type_error("HKDF-Expand failed"))
+ .map_err(|_| HkdfError::HkdfExpandFailed)
},
_ => {
- Err(type_error(format!("Unsupported digest: {}", digest_algorithm)))
+ Err(HkdfError::UnsupportedDigest(digest_algorithm.to_string()))
}
)
}
@@ -481,7 +518,7 @@ pub fn op_node_hkdf(
#[buffer] salt: &[u8],
#[buffer] info: &[u8],
#[buffer] okm: &mut [u8],
-) -> Result<(), AnyError> {
+) -> Result<(), HkdfError> {
hkdf_sync(digest_algorithm, handle, salt, info, okm)
}
@@ -493,7 +530,7 @@ pub async fn op_node_hkdf_async(
#[buffer] salt: JsBuffer,
#[buffer] info: JsBuffer,
#[number] okm_len: usize,
-) -> Result<ToJsBuffer, AnyError> {
+) -> Result<ToJsBuffer, HkdfError> {
let handle = handle.clone();
spawn_blocking(move || {
let mut okm = vec![0u8; okm_len];
@@ -509,27 +546,24 @@ pub fn op_node_dh_compute_secret(
#[buffer] prime: JsBuffer,
#[buffer] private_key: JsBuffer,
#[buffer] their_public_key: JsBuffer,
-) -> Result<ToJsBuffer, AnyError> {
+) -> ToJsBuffer {
let pubkey: BigUint = BigUint::from_bytes_be(their_public_key.as_ref());
let privkey: BigUint = BigUint::from_bytes_be(private_key.as_ref());
let primei: BigUint = BigUint::from_bytes_be(prime.as_ref());
let shared_secret: BigUint = pubkey.modpow(&privkey, &primei);
- Ok(shared_secret.to_bytes_be().into())
+ shared_secret.to_bytes_be().into()
}
#[op2(fast)]
#[number]
-pub fn op_node_random_int(
- #[number] min: i64,
- #[number] max: i64,
-) -> Result<i64, AnyError> {
+pub fn op_node_random_int(#[number] min: i64, #[number] max: i64) -> i64 {
let mut rng = rand::thread_rng();
// Uniform distribution is required to avoid Modulo Bias
// https://en.wikipedia.org/wiki/Fisher–Yates_shuffle#Modulo_bias
let dist = Uniform::from(min..max);
- Ok(dist.sample(&mut rng))
+ dist.sample(&mut rng)
}
#[allow(clippy::too_many_arguments)]
@@ -542,7 +576,7 @@ fn scrypt(
parallelization: u32,
_maxmem: u32,
output_buffer: &mut [u8],
-) -> Result<(), AnyError> {
+) -> Result<(), deno_core::error::AnyError> {
// Construct Params
let params = scrypt::Params::new(
cost as u8,
@@ -573,7 +607,7 @@ pub fn op_node_scrypt_sync(
#[smi] parallelization: u32,
#[smi] maxmem: u32,
#[anybuffer] output_buffer: &mut [u8],
-) -> Result<(), AnyError> {
+) -> Result<(), deno_core::error::AnyError> {
scrypt(
password,
salt,
@@ -586,6 +620,14 @@ pub fn op_node_scrypt_sync(
)
}
+#[derive(Debug, thiserror::Error)]
+pub enum ScryptAsyncError {
+ #[error(transparent)]
+ Join(#[from] tokio::task::JoinError),
+ #[error(transparent)]
+ Other(deno_core::error::AnyError),
+}
+
#[op2(async)]
#[serde]
pub async fn op_node_scrypt_async(
@@ -596,10 +638,11 @@ pub async fn op_node_scrypt_async(
#[smi] block_size: u32,
#[smi] parallelization: u32,
#[smi] maxmem: u32,
-) -> Result<ToJsBuffer, AnyError> {
+) -> Result<ToJsBuffer, ScryptAsyncError> {
spawn_blocking(move || {
let mut output_buffer = vec![0u8; keylen as usize];
- let res = scrypt(
+
+ scrypt(
password,
salt,
keylen,
@@ -608,25 +651,30 @@ pub async fn op_node_scrypt_async(
parallelization,
maxmem,
&mut output_buffer,
- );
-
- if res.is_ok() {
- Ok(output_buffer.into())
- } else {
- // TODO(lev): rethrow the error?
- Err(generic_error("scrypt failure"))
- }
+ )
+ .map(|_| output_buffer.into())
+ .map_err(ScryptAsyncError::Other)
})
.await?
}
+#[derive(Debug, thiserror::Error)]
+pub enum EcdhEncodePubKey {
+ #[error("Invalid public key")]
+ InvalidPublicKey,
+ #[error("Unsupported curve")]
+ UnsupportedCurve,
+ #[error(transparent)]
+ Sec1(#[from] sec1::Error),
+}
+
#[op2]
#[buffer]
pub fn op_node_ecdh_encode_pubkey(
#[string] curve: &str,
#[buffer] pubkey: &[u8],
compress: bool,
-) -> Result<Vec<u8>, AnyError> {
+) -> Result<Vec<u8>, EcdhEncodePubKey> {
use elliptic_curve::sec1::FromEncodedPoint;
match curve {
@@ -639,7 +687,7 @@ pub fn op_node_ecdh_encode_pubkey(
);
// CtOption does not expose its variants.
if pubkey.is_none().into() {
- return Err(type_error("Invalid public key"));
+ return Err(EcdhEncodePubKey::InvalidPublicKey);
}
let pubkey = pubkey.unwrap();
@@ -652,7 +700,7 @@ pub fn op_node_ecdh_encode_pubkey(
);
// CtOption does not expose its variants.
if pubkey.is_none().into() {
- return Err(type_error("Invalid public key"));
+ return Err(EcdhEncodePubKey::InvalidPublicKey);
}
let pubkey = pubkey.unwrap();
@@ -665,7 +713,7 @@ pub fn op_node_ecdh_encode_pubkey(
);
// CtOption does not expose its variants.
if pubkey.is_none().into() {
- return Err(type_error("Invalid public key"));
+ return Err(EcdhEncodePubKey::InvalidPublicKey);
}
let pubkey = pubkey.unwrap();
@@ -678,14 +726,14 @@ pub fn op_node_ecdh_encode_pubkey(
);
// CtOption does not expose its variants.
if pubkey.is_none().into() {
- return Err(type_error("Invalid public key"));
+ return Err(EcdhEncodePubKey::InvalidPublicKey);
}
let pubkey = pubkey.unwrap();
Ok(pubkey.to_encoded_point(compress).as_ref().to_vec())
}
- &_ => Err(type_error("Unsupported curve")),
+ &_ => Err(EcdhEncodePubKey::UnsupportedCurve),
}
}
@@ -695,7 +743,7 @@ pub fn op_node_ecdh_generate_keys(
#[buffer] pubbuf: &mut [u8],
#[buffer] privbuf: &mut [u8],
#[string] format: &str,
-) -> Result<(), AnyError> {
+) -> Result<(), deno_core::error::AnyError> {
let mut rng = rand::thread_rng();
let compress = format == "compressed";
match curve {
@@ -742,7 +790,7 @@ pub fn op_node_ecdh_compute_secret(
#[buffer] this_priv: Option<JsBuffer>,
#[buffer] their_pub: &mut [u8],
#[buffer] secret: &mut [u8],
-) -> Result<(), AnyError> {
+) {
match curve {
"secp256k1" => {
let their_public_key =
@@ -760,8 +808,6 @@ pub fn op_node_ecdh_compute_secret(
their_public_key.as_affine(),
);
secret.copy_from_slice(shared_secret.raw_secret_bytes());
-
- Ok(())
}
"prime256v1" | "secp256r1" => {
let their_public_key =
@@ -776,8 +822,6 @@ pub fn op_node_ecdh_compute_secret(
their_public_key.as_affine(),
);
secret.copy_from_slice(shared_secret.raw_secret_bytes());
-
- Ok(())
}
"secp384r1" => {
let their_public_key =
@@ -792,8 +836,6 @@ pub fn op_node_ecdh_compute_secret(
their_public_key.as_affine(),
);
secret.copy_from_slice(shared_secret.raw_secret_bytes());
-
- Ok(())
}
"secp224r1" => {
let their_public_key =
@@ -808,8 +850,6 @@ pub fn op_node_ecdh_compute_secret(
their_public_key.as_affine(),
);
secret.copy_from_slice(shared_secret.raw_secret_bytes());
-
- Ok(())
}
&_ => todo!(),
}
@@ -820,7 +860,7 @@ pub fn op_node_ecdh_compute_public_key(
#[string] curve: &str,
#[buffer] privkey: &[u8],
#[buffer] pubkey: &mut [u8],
-) -> Result<(), AnyError> {
+) {
match curve {
"secp256k1" => {
let this_private_key =
@@ -828,8 +868,6 @@ pub fn op_node_ecdh_compute_public_key(
.expect("bad private key");
let public_key = this_private_key.public_key();
pubkey.copy_from_slice(public_key.to_sec1_bytes().as_ref());
-
- Ok(())
}
"prime256v1" | "secp256r1" => {
let this_private_key =
@@ -837,7 +875,6 @@ pub fn op_node_ecdh_compute_public_key(
.expect("bad private key");
let public_key = this_private_key.public_key();
pubkey.copy_from_slice(public_key.to_sec1_bytes().as_ref());
- Ok(())
}
"secp384r1" => {
let this_private_key =
@@ -845,7 +882,6 @@ pub fn op_node_ecdh_compute_public_key(
.expect("bad private key");
let public_key = this_private_key.public_key();
pubkey.copy_from_slice(public_key.to_sec1_bytes().as_ref());
- Ok(())
}
"secp224r1" => {
let this_private_key =
@@ -853,7 +889,6 @@ pub fn op_node_ecdh_compute_public_key(
.expect("bad private key");
let public_key = this_private_key.public_key();
pubkey.copy_from_slice(public_key.to_sec1_bytes().as_ref());
- Ok(())
}
&_ => todo!(),
}
@@ -874,8 +909,20 @@ pub fn op_node_gen_prime(#[number] size: usize) -> ToJsBuffer {
#[serde]
pub async fn op_node_gen_prime_async(
#[number] size: usize,
-) -> Result<ToJsBuffer, AnyError> {
- Ok(spawn_blocking(move || gen_prime(size)).await?)
+) -> Result<ToJsBuffer, tokio::task::JoinError> {
+ spawn_blocking(move || gen_prime(size)).await
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum DiffieHellmanError {
+ #[error("Expected private key")]
+ ExpectedPrivateKey,
+ #[error("Expected public key")]
+ ExpectedPublicKey,
+ #[error("DH parameters mismatch")]
+ DhParametersMismatch,
+ #[error("Unsupported key type for diffie hellman, or key type mismatch")]
+ UnsupportedKeyTypeForDiffieHellmanOrKeyTypeMismatch,
}
#[op2]
@@ -883,117 +930,134 @@ pub async fn op_node_gen_prime_async(
pub fn op_node_diffie_hellman(
#[cppgc] private: &KeyObjectHandle,
#[cppgc] public: &KeyObjectHandle,
-) -> Result<Box<[u8]>, AnyError> {
+) -> Result<Box<[u8]>, DiffieHellmanError> {
let private = private
.as_private_key()
- .ok_or_else(|| type_error("Expected private key"))?;
+ .ok_or(DiffieHellmanError::ExpectedPrivateKey)?;
let public = public
.as_public_key()
- .ok_or_else(|| type_error("Expected public key"))?;
-
- let res = match (private, &*public) {
- (
- AsymmetricPrivateKey::Ec(EcPrivateKey::P224(private)),
- AsymmetricPublicKey::Ec(EcPublicKey::P224(public)),
- ) => p224::ecdh::diffie_hellman(
- private.to_nonzero_scalar(),
- public.as_affine(),
- )
- .raw_secret_bytes()
- .to_vec()
- .into_boxed_slice(),
- (
- AsymmetricPrivateKey::Ec(EcPrivateKey::P256(private)),
- AsymmetricPublicKey::Ec(EcPublicKey::P256(public)),
- ) => p256::ecdh::diffie_hellman(
- private.to_nonzero_scalar(),
- public.as_affine(),
- )
- .raw_secret_bytes()
- .to_vec()
- .into_boxed_slice(),
- (
- AsymmetricPrivateKey::Ec(EcPrivateKey::P384(private)),
- AsymmetricPublicKey::Ec(EcPublicKey::P384(public)),
- ) => p384::ecdh::diffie_hellman(
- private.to_nonzero_scalar(),
- public.as_affine(),
- )
- .raw_secret_bytes()
- .to_vec()
- .into_boxed_slice(),
- (
- AsymmetricPrivateKey::X25519(private),
- AsymmetricPublicKey::X25519(public),
- ) => private
- .diffie_hellman(public)
- .to_bytes()
- .into_iter()
- .collect(),
- (AsymmetricPrivateKey::Dh(private), AsymmetricPublicKey::Dh(public)) => {
- if private.params.prime != public.params.prime
- || private.params.base != public.params.base
- {
- return Err(type_error("DH parameters mismatch"));
+ .ok_or(DiffieHellmanError::ExpectedPublicKey)?;
+
+ let res =
+ match (private, &*public) {
+ (
+ AsymmetricPrivateKey::Ec(EcPrivateKey::P224(private)),
+ AsymmetricPublicKey::Ec(EcPublicKey::P224(public)),
+ ) => p224::ecdh::diffie_hellman(
+ private.to_nonzero_scalar(),
+ public.as_affine(),
+ )
+ .raw_secret_bytes()
+ .to_vec()
+ .into_boxed_slice(),
+ (
+ AsymmetricPrivateKey::Ec(EcPrivateKey::P256(private)),
+ AsymmetricPublicKey::Ec(EcPublicKey::P256(public)),
+ ) => p256::ecdh::diffie_hellman(
+ private.to_nonzero_scalar(),
+ public.as_affine(),
+ )
+ .raw_secret_bytes()
+ .to_vec()
+ .into_boxed_slice(),
+ (
+ AsymmetricPrivateKey::Ec(EcPrivateKey::P384(private)),
+ AsymmetricPublicKey::Ec(EcPublicKey::P384(public)),
+ ) => p384::ecdh::diffie_hellman(
+ private.to_nonzero_scalar(),
+ public.as_affine(),
+ )
+ .raw_secret_bytes()
+ .to_vec()
+ .into_boxed_slice(),
+ (
+ AsymmetricPrivateKey::X25519(private),
+ AsymmetricPublicKey::X25519(public),
+ ) => private
+ .diffie_hellman(public)
+ .to_bytes()
+ .into_iter()
+ .collect(),
+ (AsymmetricPrivateKey::Dh(private), AsymmetricPublicKey::Dh(public)) => {
+ if private.params.prime != public.params.prime
+ || private.params.base != public.params.base
+ {
+ return Err(DiffieHellmanError::DhParametersMismatch);
+ }
+
+ // OSIP - Octet-String-to-Integer primitive
+ let public_key = public.key.clone().into_vec();
+ let pubkey = BigUint::from_bytes_be(&public_key);
+
+ // Exponentiation (z = y^x mod p)
+ let prime = BigUint::from_bytes_be(private.params.prime.as_bytes());
+ let private_key = private.key.clone().into_vec();
+ let private_key = BigUint::from_bytes_be(&private_key);
+ let shared_secret = pubkey.modpow(&private_key, &prime);
+
+ shared_secret.to_bytes_be().into()
}
-
- // OSIP - Octet-String-to-Integer primitive
- let public_key = public.key.clone().into_vec();
- let pubkey = BigUint::from_bytes_be(&public_key);
-
- // Exponentiation (z = y^x mod p)
- let prime = BigUint::from_bytes_be(private.params.prime.as_bytes());
- let private_key = private.key.clone().into_vec();
- let private_key = BigUint::from_bytes_be(&private_key);
- let shared_secret = pubkey.modpow(&private_key, &prime);
-
- shared_secret.to_bytes_be().into()
- }
- _ => {
- return Err(type_error(
- "Unsupported key type for diffie hellman, or key type mismatch",
- ))
- }
- };
+ _ => return Err(
+ DiffieHellmanError::UnsupportedKeyTypeForDiffieHellmanOrKeyTypeMismatch,
+ ),
+ };
Ok(res)
}
+#[derive(Debug, thiserror::Error)]
+pub enum SignEd25519Error {
+ #[error("Expected private key")]
+ ExpectedPrivateKey,
+ #[error("Expected Ed25519 private key")]
+ ExpectedEd25519PrivateKey,
+ #[error("Invalid Ed25519 private key")]
+ InvalidEd25519PrivateKey,
+}
+
#[op2(fast)]
pub fn op_node_sign_ed25519(
#[cppgc] key: &KeyObjectHandle,
#[buffer] data: &[u8],
#[buffer] signature: &mut [u8],
-) -> Result<(), AnyError> {
+) -> Result<(), SignEd25519Error> {
let private = key
.as_private_key()
- .ok_or_else(|| type_error("Expected private key"))?;
+ .ok_or(SignEd25519Error::ExpectedPrivateKey)?;
let ed25519 = match private {
AsymmetricPrivateKey::Ed25519(private) => private,
- _ => return Err(type_error("Expected Ed25519 private key")),
+ _ => return Err(SignEd25519Error::ExpectedEd25519PrivateKey),
};
let pair = Ed25519KeyPair::from_seed_unchecked(ed25519.as_bytes().as_slice())
- .map_err(|_| type_error("Invalid Ed25519 private key"))?;
+ .map_err(|_| SignEd25519Error::InvalidEd25519PrivateKey)?;
signature.copy_from_slice(pair.sign(data).as_ref());
Ok(())
}
+#[derive(Debug, thiserror::Error)]
+pub enum VerifyEd25519Error {
+ #[error("Expected public key")]
+ ExpectedPublicKey,
+ #[error("Expected Ed25519 public key")]
+ ExpectedEd25519PublicKey,
+}
+
#[op2(fast)]
pub fn op_node_verify_ed25519(
#[cppgc] key: &KeyObjectHandle,
#[buffer] data: &[u8],
#[buffer] signature: &[u8],
-) -> Result<bool, AnyError> {
+) -> Result<bool, VerifyEd25519Error> {
let public = key
.as_public_key()
- .ok_or_else(|| type_error("Expected public key"))?;
+ .ok_or(VerifyEd25519Error::ExpectedPublicKey)?;
let ed25519 = match &*public {
AsymmetricPublicKey::Ed25519(public) => public,
- _ => return Err(type_error("Expected Ed25519 public key")),
+ _ => return Err(VerifyEd25519Error::ExpectedEd25519PublicKey),
};
let verified = ring::signature::UnparsedPublicKey::new(
diff --git a/ext/node/ops/crypto/sign.rs b/ext/node/ops/crypto/sign.rs
index 31744f86b..30094c076 100644
--- a/ext/node/ops/crypto/sign.rs
+++ b/ext/node/ops/crypto/sign.rs
@@ -1,7 +1,4 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-use deno_core::error::generic_error;
-use deno_core::error::type_error;
-use deno_core::error::AnyError;
use rand::rngs::OsRng;
use rsa::signature::hazmat::PrehashSigner as _;
use rsa::signature::hazmat::PrehashVerifier as _;
@@ -26,7 +23,7 @@ use elliptic_curve::FieldBytesSize;
fn dsa_signature<C: elliptic_curve::PrimeCurve>(
encoding: u32,
signature: ecdsa::Signature<C>,
-) -> Result<Box<[u8]>, AnyError>
+) -> Result<Box<[u8]>, KeyObjectHandlePrehashedSignAndVerifyError>
where
MaxSize<C>: ArrayLength<u8>,
<FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
@@ -36,10 +33,54 @@ where
0 => Ok(signature.to_der().to_bytes().to_vec().into_boxed_slice()),
// IEEE P1363
1 => Ok(signature.to_bytes().to_vec().into_boxed_slice()),
- _ => Err(type_error("invalid DSA signature encoding")),
+ _ => Err(
+ KeyObjectHandlePrehashedSignAndVerifyError::InvalidDsaSignatureEncoding,
+ ),
}
}
+#[derive(Debug, thiserror::Error)]
+pub enum KeyObjectHandlePrehashedSignAndVerifyError {
+ #[error("invalid DSA signature encoding")]
+ InvalidDsaSignatureEncoding,
+ #[error("key is not a private key")]
+ KeyIsNotPrivate,
+ #[error("digest not allowed for RSA signature: {0}")]
+ DigestNotAllowedForRsaSignature(String),
+ #[error("failed to sign digest with RSA")]
+ FailedToSignDigestWithRsa,
+ #[error("digest not allowed for RSA-PSS signature: {0}")]
+ DigestNotAllowedForRsaPssSignature(String),
+ #[error("failed to sign digest with RSA-PSS")]
+ FailedToSignDigestWithRsaPss,
+ #[error("failed to sign digest with DSA")]
+ FailedToSignDigestWithDsa,
+ #[error("rsa-pss with different mf1 hash algorithm and hash algorithm is not supported")]
+ RsaPssHashAlgorithmUnsupported,
+ #[error(
+ "private key does not allow {actual} to be used, expected {expected}"
+ )]
+ PrivateKeyDisallowsUsage { actual: String, expected: String },
+ #[error("failed to sign digest")]
+ FailedToSignDigest,
+ #[error("x25519 key cannot be used for signing")]
+ X25519KeyCannotBeUsedForSigning,
+ #[error("Ed25519 key cannot be used for prehashed signing")]
+ Ed25519KeyCannotBeUsedForPrehashedSigning,
+ #[error("DH key cannot be used for signing")]
+ DhKeyCannotBeUsedForSigning,
+ #[error("key is not a public or private key")]
+ KeyIsNotPublicOrPrivate,
+ #[error("Invalid DSA signature")]
+ InvalidDsaSignature,
+ #[error("x25519 key cannot be used for verification")]
+ X25519KeyCannotBeUsedForVerification,
+ #[error("Ed25519 key cannot be used for prehashed verification")]
+ Ed25519KeyCannotBeUsedForPrehashedVerification,
+ #[error("DH key cannot be used for verification")]
+ DhKeyCannotBeUsedForVerification,
+}
+
impl KeyObjectHandle {
pub fn sign_prehashed(
&self,
@@ -47,10 +88,10 @@ impl KeyObjectHandle {
digest: &[u8],
pss_salt_length: Option<u32>,
dsa_signature_encoding: u32,
- ) -> Result<Box<[u8]>, AnyError> {
+ ) -> Result<Box<[u8]>, KeyObjectHandlePrehashedSignAndVerifyError> {
let private_key = self
.as_private_key()
- .ok_or_else(|| type_error("key is not a private key"))?;
+ .ok_or(KeyObjectHandlePrehashedSignAndVerifyError::KeyIsNotPrivate)?;
match private_key {
AsymmetricPrivateKey::Rsa(key) => {
@@ -63,17 +104,14 @@ impl KeyObjectHandle {
rsa::pkcs1v15::Pkcs1v15Sign::new::<D>()
},
_ => {
- return Err(type_error(format!(
- "digest not allowed for RSA signature: {}",
- digest_type
- )))
+ return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaSignature(digest_type.to_string()))
}
)
};
let signature = signer
.sign(Some(&mut OsRng), key, digest)
- .map_err(|_| generic_error("failed to sign digest with RSA"))?;
+ .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithRsa)?;
Ok(signature.into())
}
AsymmetricPrivateKey::RsaPss(key) => {
@@ -81,9 +119,7 @@ impl KeyObjectHandle {
let mut salt_length = None;
if let Some(details) = &key.details {
if details.hash_algorithm != details.mf1_hash_algorithm {
- return Err(type_error(
- "rsa-pss with different mf1 hash algorithm and hash algorithm is not supported",
- ));
+ return Err(KeyObjectHandlePrehashedSignAndVerifyError::RsaPssHashAlgorithmUnsupported);
}
hash_algorithm = Some(details.hash_algorithm);
salt_length = Some(details.salt_length as usize);
@@ -96,10 +132,10 @@ impl KeyObjectHandle {
fn <D>(algorithm: Option<RsaPssHashAlgorithm>) {
if let Some(hash_algorithm) = hash_algorithm.take() {
if Some(hash_algorithm) != algorithm {
- return Err(type_error(format!(
- "private key does not allow {} to be used, expected {}",
- digest_type, hash_algorithm.as_str()
- )));
+ return Err(KeyObjectHandlePrehashedSignAndVerifyError::PrivateKeyDisallowsUsage {
+ actual: digest_type.to_string(),
+ expected: hash_algorithm.as_str().to_string(),
+ });
}
}
if let Some(salt_length) = salt_length {
@@ -109,15 +145,12 @@ impl KeyObjectHandle {
}
},
_ => {
- return Err(type_error(format!(
- "digest not allowed for RSA-PSS signature: {}",
- digest_type
- )))
+ return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaPssSignature(digest_type.to_string()));
}
);
let signature = pss
.sign(Some(&mut OsRng), &key.key, digest)
- .map_err(|_| generic_error("failed to sign digest with RSA-PSS"))?;
+ .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithRsaPss)?;
Ok(signature.into())
}
AsymmetricPrivateKey::Dsa(key) => {
@@ -127,15 +160,12 @@ impl KeyObjectHandle {
key.sign_prehashed_rfc6979::<D>(digest)
},
_ => {
- return Err(type_error(format!(
- "digest not allowed for RSA signature: {}",
- digest_type
- )))
+ return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaSignature(digest_type.to_string()))
}
);
let signature =
- res.map_err(|_| generic_error("failed to sign digest with DSA"))?;
+ res.map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithDsa)?;
Ok(signature.into())
}
AsymmetricPrivateKey::Ec(key) => match key {
@@ -143,7 +173,7 @@ impl KeyObjectHandle {
let signing_key = p224::ecdsa::SigningKey::from(key);
let signature: p224::ecdsa::Signature = signing_key
.sign_prehash(digest)
- .map_err(|_| type_error("failed to sign digest"))?;
+ .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest)?;
dsa_signature(dsa_signature_encoding, signature)
}
@@ -151,7 +181,7 @@ impl KeyObjectHandle {
let signing_key = p256::ecdsa::SigningKey::from(key);
let signature: p256::ecdsa::Signature = signing_key
.sign_prehash(digest)
- .map_err(|_| type_error("failed to sign digest"))?;
+ .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest)?;
dsa_signature(dsa_signature_encoding, signature)
}
@@ -159,19 +189,17 @@ impl KeyObjectHandle {
let signing_key = p384::ecdsa::SigningKey::from(key);
let signature: p384::ecdsa::Signature = signing_key
.sign_prehash(digest)
- .map_err(|_| type_error("failed to sign digest"))?;
+ .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest)?;
dsa_signature(dsa_signature_encoding, signature)
}
},
AsymmetricPrivateKey::X25519(_) => {
- Err(type_error("x25519 key cannot be used for signing"))
+ Err(KeyObjectHandlePrehashedSignAndVerifyError::X25519KeyCannotBeUsedForSigning)
}
- AsymmetricPrivateKey::Ed25519(_) => Err(type_error(
- "Ed25519 key cannot be used for prehashed signing",
- )),
+ AsymmetricPrivateKey::Ed25519(_) => Err(KeyObjectHandlePrehashedSignAndVerifyError::Ed25519KeyCannotBeUsedForPrehashedSigning),
AsymmetricPrivateKey::Dh(_) => {
- Err(type_error("DH key cannot be used for signing"))
+ Err(KeyObjectHandlePrehashedSignAndVerifyError::DhKeyCannotBeUsedForSigning)
}
}
}
@@ -183,10 +211,10 @@ impl KeyObjectHandle {
signature: &[u8],
pss_salt_length: Option<u32>,
dsa_signature_encoding: u32,
- ) -> Result<bool, AnyError> {
- let public_key = self
- .as_public_key()
- .ok_or_else(|| type_error("key is not a public or private key"))?;
+ ) -> Result<bool, KeyObjectHandlePrehashedSignAndVerifyError> {
+ let public_key = self.as_public_key().ok_or(
+ KeyObjectHandlePrehashedSignAndVerifyError::KeyIsNotPublicOrPrivate,
+ )?;
match &*public_key {
AsymmetricPublicKey::Rsa(key) => {
@@ -199,10 +227,7 @@ impl KeyObjectHandle {
rsa::pkcs1v15::Pkcs1v15Sign::new::<D>()
},
_ => {
- return Err(type_error(format!(
- "digest not allowed for RSA signature: {}",
- digest_type
- )))
+ return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaSignature(digest_type.to_string()))
}
)
};
@@ -214,9 +239,7 @@ impl KeyObjectHandle {
let mut salt_length = None;
if let Some(details) = &key.details {
if details.hash_algorithm != details.mf1_hash_algorithm {
- return Err(type_error(
- "rsa-pss with different mf1 hash algorithm and hash algorithm is not supported",
- ));
+ return Err(KeyObjectHandlePrehashedSignAndVerifyError::RsaPssHashAlgorithmUnsupported);
}
hash_algorithm = Some(details.hash_algorithm);
salt_length = Some(details.salt_length as usize);
@@ -229,10 +252,10 @@ impl KeyObjectHandle {
fn <D>(algorithm: Option<RsaPssHashAlgorithm>) {
if let Some(hash_algorithm) = hash_algorithm.take() {
if Some(hash_algorithm) != algorithm {
- return Err(type_error(format!(
- "private key does not allow {} to be used, expected {}",
- digest_type, hash_algorithm.as_str()
- )));
+ return Err(KeyObjectHandlePrehashedSignAndVerifyError::PrivateKeyDisallowsUsage {
+ actual: digest_type.to_string(),
+ expected: hash_algorithm.as_str().to_string(),
+ });
}
}
if let Some(salt_length) = salt_length {
@@ -242,17 +265,14 @@ impl KeyObjectHandle {
}
},
_ => {
- return Err(type_error(format!(
- "digest not allowed for RSA-PSS signature: {}",
- digest_type
- )))
+ return Err(KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaPssSignature(digest_type.to_string()));
}
);
Ok(pss.verify(&key.key, digest, signature).is_ok())
}
AsymmetricPublicKey::Dsa(key) => {
let signature = dsa::Signature::from_der(signature)
- .map_err(|_| type_error("Invalid DSA signature"))?;
+ .map_err(|_| KeyObjectHandlePrehashedSignAndVerifyError::InvalidDsaSignature)?;
Ok(key.verify_prehash(digest, &signature).is_ok())
}
AsymmetricPublicKey::Ec(key) => match key {
@@ -294,13 +314,11 @@ impl KeyObjectHandle {
}
},
AsymmetricPublicKey::X25519(_) => {
- Err(type_error("x25519 key cannot be used for verification"))
+ Err(KeyObjectHandlePrehashedSignAndVerifyError::X25519KeyCannotBeUsedForVerification)
}
- AsymmetricPublicKey::Ed25519(_) => Err(type_error(
- "Ed25519 key cannot be used for prehashed verification",
- )),
+ AsymmetricPublicKey::Ed25519(_) => Err(KeyObjectHandlePrehashedSignAndVerifyError::Ed25519KeyCannotBeUsedForPrehashedVerification),
AsymmetricPublicKey::Dh(_) => {
- Err(type_error("DH key cannot be used for verification"))
+ Err(KeyObjectHandlePrehashedSignAndVerifyError::DhKeyCannotBeUsedForVerification)
}
}
}
diff --git a/ext/node/ops/crypto/x509.rs b/ext/node/ops/crypto/x509.rs
index b44ff3a4b..ab8e52f70 100644
--- a/ext/node/ops/crypto/x509.rs
+++ b/ext/node/ops/crypto/x509.rs
@@ -1,11 +1,11 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-use deno_core::error::AnyError;
use deno_core::op2;
use x509_parser::der_parser::asn1_rs::Any;
use x509_parser::der_parser::asn1_rs::Tag;
use x509_parser::der_parser::oid::Oid;
+pub use x509_parser::error::X509Error;
use x509_parser::extensions;
use x509_parser::pem;
use x509_parser::prelude::*;
@@ -65,7 +65,7 @@ impl<'a> Deref for CertificateView<'a> {
#[cppgc]
pub fn op_node_x509_parse(
#[buffer] buf: &[u8],
-) -> Result<Certificate, AnyError> {
+) -> Result<Certificate, X509Error> {
let source = match pem::parse_x509_pem(buf) {
Ok((_, pem)) => CertificateSources::Pem(pem),
Err(_) => CertificateSources::Der(buf.to_vec().into_boxed_slice()),
@@ -81,7 +81,7 @@ pub fn op_node_x509_parse(
X509Certificate::from_der(buf).map(|(_, cert)| cert)?
}
};
- Ok::<_, AnyError>(CertificateView { cert })
+ Ok::<_, X509Error>(CertificateView { cert })
},
)?;
@@ -89,23 +89,23 @@ pub fn op_node_x509_parse(
}
#[op2(fast)]
-pub fn op_node_x509_ca(#[cppgc] cert: &Certificate) -> Result<bool, AnyError> {
+pub fn op_node_x509_ca(#[cppgc] cert: &Certificate) -> bool {
let cert = cert.inner.get().deref();
- Ok(cert.is_ca())
+ cert.is_ca()
}
#[op2(fast)]
pub fn op_node_x509_check_email(
#[cppgc] cert: &Certificate,
#[string] email: &str,
-) -> Result<bool, AnyError> {
+) -> bool {
let cert = cert.inner.get().deref();
let subject = cert.subject();
if subject
.iter_email()
.any(|e| e.as_str().unwrap_or("") == email)
{
- return Ok(true);
+ return true;
}
let subject_alt = cert
@@ -121,62 +121,60 @@ pub fn op_node_x509_check_email(
for name in &subject_alt.general_names {
if let extensions::GeneralName::RFC822Name(n) = name {
if *n == email {
- return Ok(true);
+ return true;
}
}
}
}
- Ok(false)
+ false
}
#[op2]
#[string]
-pub fn op_node_x509_fingerprint(
- #[cppgc] cert: &Certificate,
-) -> Result<Option<String>, AnyError> {
- Ok(cert.fingerprint::<sha1::Sha1>())
+pub fn op_node_x509_fingerprint(#[cppgc] cert: &Certificate) -> Option<String> {
+ cert.fingerprint::<sha1::Sha1>()
}
#[op2]
#[string]
pub fn op_node_x509_fingerprint256(
#[cppgc] cert: &Certificate,
-) -> Result<Option<String>, AnyError> {
- Ok(cert.fingerprint::<sha2::Sha256>())
+) -> Option<String> {
+ cert.fingerprint::<sha2::Sha256>()
}
#[op2]
#[string]
pub fn op_node_x509_fingerprint512(
#[cppgc] cert: &Certificate,
-) -> Result<Option<String>, AnyError> {
- Ok(cert.fingerprint::<sha2::Sha512>())
+) -> Option<String> {
+ cert.fingerprint::<sha2::Sha512>()
}
#[op2]
#[string]
pub fn op_node_x509_get_issuer(
#[cppgc] cert: &Certificate,
-) -> Result<String, AnyError> {
+) -> Result<String, X509Error> {
let cert = cert.inner.get().deref();
- Ok(x509name_to_string(cert.issuer(), oid_registry())?)
+ x509name_to_string(cert.issuer(), oid_registry())
}
#[op2]
#[string]
pub fn op_node_x509_get_subject(
#[cppgc] cert: &Certificate,
-) -> Result<String, AnyError> {
+) -> Result<String, X509Error> {
let cert = cert.inner.get().deref();
- Ok(x509name_to_string(cert.subject(), oid_registry())?)
+ x509name_to_string(cert.subject(), oid_registry())
}
#[op2]
#[cppgc]
pub fn op_node_x509_public_key(
#[cppgc] cert: &Certificate,
-) -> Result<KeyObjectHandle, AnyError> {
+) -> Result<KeyObjectHandle, super::keys::X509PublicKeyError> {
let cert = cert.inner.get().deref();
let public_key = &cert.tbs_certificate.subject_pki;
@@ -245,37 +243,29 @@ fn x509name_to_string(
#[op2]
#[string]
-pub fn op_node_x509_get_valid_from(
- #[cppgc] cert: &Certificate,
-) -> Result<String, AnyError> {
+pub fn op_node_x509_get_valid_from(#[cppgc] cert: &Certificate) -> String {
let cert = cert.inner.get().deref();
- Ok(cert.validity().not_before.to_string())
+ cert.validity().not_before.to_string()
}
#[op2]
#[string]
-pub fn op_node_x509_get_valid_to(
- #[cppgc] cert: &Certificate,
-) -> Result<String, AnyError> {
+pub fn op_node_x509_get_valid_to(#[cppgc] cert: &Certificate) -> String {
let cert = cert.inner.get().deref();
- Ok(cert.validity().not_after.to_string())
+ cert.validity().not_after.to_string()
}
#[op2]
#[string]
-pub fn op_node_x509_get_serial_number(
- #[cppgc] cert: &Certificate,
-) -> Result<String, AnyError> {
+pub fn op_node_x509_get_serial_number(#[cppgc] cert: &Certificate) -> String {
let cert = cert.inner.get().deref();
let mut s = cert.serial.to_str_radix(16);
s.make_ascii_uppercase();
- Ok(s)
+ s
}
#[op2(fast)]
-pub fn op_node_x509_key_usage(
- #[cppgc] cert: &Certificate,
-) -> Result<u16, AnyError> {
+pub fn op_node_x509_key_usage(#[cppgc] cert: &Certificate) -> u16 {
let cert = cert.inner.get().deref();
let key_usage = cert
.extensions()
@@ -286,5 +276,5 @@ pub fn op_node_x509_key_usage(
_ => None,
});
- Ok(key_usage.map(|k| k.flags).unwrap_or(0))
+ key_usage.map(|k| k.flags).unwrap_or(0)
}