diff options
Diffstat (limited to 'ext/node')
-rw-r--r-- | ext/node/crypto/mod.rs | 54 | ||||
-rw-r--r-- | ext/node/lib.rs | 1 | ||||
-rw-r--r-- | ext/node/polyfills/internal/crypto/sig.ts | 72 |
3 files changed, 105 insertions, 22 deletions
diff --git a/ext/node/crypto/mod.rs b/ext/node/crypto/mod.rs index f818b96af..b45f36144 100644 --- a/ext/node/crypto/mod.rs +++ b/ext/node/crypto/mod.rs @@ -309,7 +309,7 @@ pub fn op_node_sign( use signature::hazmat::PrehashSigner; let key = match key_format { "pem" => RsaPrivateKey::from_pkcs8_pem((&key).try_into()?) - .map_err(|_| type_error("Invalid RSA key"))?, + .map_err(|_| type_error("Invalid RSA private key"))?, // TODO(kt3k): Support der and jwk formats _ => { return Err(type_error(format!( @@ -353,6 +353,58 @@ pub fn op_node_sign( } } +#[op] +fn op_node_verify( + digest: &[u8], + digest_type: &str, + key: StringOrBuffer, + key_type: &str, + key_format: &str, + signature: &[u8], +) -> Result<bool, AnyError> { + match key_type { + "rsa" => { + use rsa::pkcs1v15::VerifyingKey; + use signature::hazmat::PrehashVerifier; + let key = match key_format { + "pem" => RsaPublicKey::from_public_key_pem((&key).try_into()?) + .map_err(|_| type_error("Invalid RSA public key"))?, + // TODO(kt3k): Support der and jwk formats + _ => { + return Err(type_error(format!( + "Unsupported key format: {}", + key_format + ))) + } + }; + Ok(match digest_type { + "sha224" => VerifyingKey::<sha2::Sha224>::new_with_prefix(key) + .verify_prehash(digest, &signature.to_vec().try_into()?) + .is_ok(), + "sha256" => VerifyingKey::<sha2::Sha256>::new_with_prefix(key) + .verify_prehash(digest, &signature.to_vec().try_into()?) + .is_ok(), + "sha384" => VerifyingKey::<sha2::Sha384>::new_with_prefix(key) + .verify_prehash(digest, &signature.to_vec().try_into()?) + .is_ok(), + "sha512" => VerifyingKey::<sha2::Sha512>::new_with_prefix(key) + .verify_prehash(digest, &signature.to_vec().try_into()?) + .is_ok(), + _ => { + return Err(type_error(format!( + "Unknown digest algorithm: {}", + digest_type + ))) + } + }) + } + _ => Err(type_error(format!( + "Verifying with {} keys is not supported yet", + key_type + ))), + } +} + fn pbkdf2_sync( password: &[u8], salt: &[u8], diff --git a/ext/node/lib.rs b/ext/node/lib.rs index f4b4d0a39..b09cb1c90 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -194,6 +194,7 @@ deno_core::extension!(deno_node, crypto::op_node_generate_secret, crypto::op_node_generate_secret_async, crypto::op_node_sign, + crypto::op_node_verify, crypto::op_node_random_int, crypto::x509::op_node_x509_parse, crypto::x509::op_node_x509_ca, diff --git a/ext/node/polyfills/internal/crypto/sig.ts b/ext/node/polyfills/internal/crypto/sig.ts index e49128b1e..2996cb2ca 100644 --- a/ext/node/polyfills/internal/crypto/sig.ts +++ b/ext/node/polyfills/internal/crypto/sig.ts @@ -67,7 +67,7 @@ export class Sign extends Writable { } sign( - privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput, + privateKey: BinaryLike | SignKeyObjectInput | SignPrivateKeyInput, encoding?: BinaryToTextEncoding, ): Buffer | string { let keyData: Uint8Array; @@ -75,7 +75,8 @@ export class Sign extends Writable { let keyFormat: KeyFormat; if (typeof privateKey === "string" || isArrayBufferView(privateKey)) { // if the key is BinaryLike, interpret it as a PEM encoded RSA key - keyData = privateKey; + // deno-lint-ignore no-explicit-any + keyData = privateKey as any; keyType = "rsa"; keyFormat = "pem"; } else { @@ -103,35 +104,64 @@ export class Sign extends Writable { } export class Verify extends Writable { + hash: Hash; + #digestType: string; + constructor(algorithm: string, _options?: WritableOptions) { validateString(algorithm, "algorithm"); - super(); + super({ + write(chunk, enc, callback) { + this.update(chunk, enc); + callback(); + }, + }); + + algorithm = algorithm.toLowerCase(); - notImplemented("crypto.Verify"); + if (algorithm.startsWith("rsa-")) { + // Allows RSA-[digest_algorithm] as a valid algorithm + algorithm = algorithm.slice(4); + } + + this.#digestType = algorithm; + this.hash = createHash(this.#digestType); } - update(data: BinaryLike): this; - update(data: string, inputEncoding: Encoding): this; - update(_data: BinaryLike, _inputEncoding?: string): this { - notImplemented("crypto.Sign.prototype.update"); + update(data: BinaryLike, encoding?: string): this { + this.hash.update(data, encoding); + return this; } verify( - object: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput, - signature: ArrayBufferView, - ): boolean; - verify( - object: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput, - signature: string, - signatureEncoding?: BinaryToTextEncoding, - ): boolean; - verify( - _object: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput, - _signature: ArrayBufferView | string, - _signatureEncoding?: BinaryToTextEncoding, + publicKey: BinaryLike | VerifyKeyObjectInput | VerifyPublicKeyInput, + signature: BinaryLike, + encoding?: BinaryToTextEncoding, ): boolean { - notImplemented("crypto.Sign.prototype.sign"); + let keyData: BinaryLike; + let keyType: KeyType; + let keyFormat: KeyFormat; + if (typeof publicKey === "string" || isArrayBufferView(publicKey)) { + // if the key is BinaryLike, interpret it as a PEM encoded RSA key + // deno-lint-ignore no-explicit-any + keyData = publicKey as any; + keyType = "rsa"; + keyFormat = "pem"; + } else { + // TODO(kt3k): Add support for the case when publicKey is a KeyObject, + // CryptoKey, etc + notImplemented( + "crypto.Verify.prototype.verify with non BinaryLike input", + ); + } + return ops.op_node_verify( + this.hash.digest(), + this.#digestType, + keyData!, + keyType, + keyFormat, + Buffer.from(signature, encoding), + ); } } |