summaryrefslogtreecommitdiff
path: root/ext/node
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node')
-rw-r--r--ext/node/Cargo.toml1
-rw-r--r--ext/node/crypto/mod.rs58
-rw-r--r--ext/node/lib.rs3
-rw-r--r--ext/node/polyfills/internal/crypto/hash.ts2
-rw-r--r--ext/node/polyfills/internal/crypto/sig.ts66
5 files changed, 114 insertions, 16 deletions
diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml
index d0a5a40fb..be3231087 100644
--- a/ext/node/Cargo.toml
+++ b/ext/node/Cargo.toml
@@ -39,5 +39,6 @@ serde = "1.0.149"
sha-1 = "0.10.0"
sha2 = "0.10.6"
sha3 = "0.10.5"
+signature.workspace = true
tokio.workspace = true
typenum = "1.15.0"
diff --git a/ext/node/crypto/mod.rs b/ext/node/crypto/mod.rs
index 352d9c31a..3529a3aa4 100644
--- a/ext/node/crypto/mod.rs
+++ b/ext/node/crypto/mod.rs
@@ -290,6 +290,64 @@ pub fn op_node_decipheriv_final(
context.r#final(input, output)
}
+#[op]
+pub fn op_node_sign(
+ digest: &[u8],
+ digest_type: &str,
+ key: StringOrBuffer,
+ key_type: &str,
+ key_format: &str,
+) -> Result<ZeroCopyBuf, AnyError> {
+ match key_type {
+ "rsa" => {
+ use rsa::pkcs1v15::SigningKey;
+ use signature::hazmat::PrehashSigner;
+ let key = match key_format {
+ "pem" => RsaPrivateKey::from_pkcs8_pem((&key).try_into()?)
+ .map_err(|_| type_error("Invalid RSA key"))?,
+ // TODO(kt3k): Support der and jwk formats
+ _ => {
+ return Err(type_error(format!(
+ "Unsupported key format: {}",
+ key_format
+ )))
+ }
+ };
+ Ok(
+ match digest_type {
+ "sha224" => {
+ let signing_key = SigningKey::<sha2::Sha224>::new_with_prefix(key);
+ signing_key.sign_prehash(digest)?.to_vec()
+ }
+ "sha256" => {
+ let signing_key = SigningKey::<sha2::Sha256>::new_with_prefix(key);
+ signing_key.sign_prehash(digest)?.to_vec()
+ }
+ "sha384" => {
+ let signing_key = SigningKey::<sha2::Sha384>::new_with_prefix(key);
+ signing_key.sign_prehash(digest)?.to_vec()
+ }
+ "sha512" => {
+ let signing_key = SigningKey::<sha2::Sha512>::new_with_prefix(key);
+ signing_key.sign_prehash(digest)?.to_vec()
+ }
+ _ => {
+ return Err(type_error(format!(
+ "Unknown digest algorithm: {}",
+ digest_type
+ )))
+ }
+ }
+ .into(),
+ )
+ }
+ _ => Err(type_error(format!(
+ "Signing 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 b83a86a5b..0507f4a88 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -119,6 +119,7 @@ deno_core::extension!(deno_node,
crypto::op_node_check_prime_bytes_async,
crypto::op_node_pbkdf2,
crypto::op_node_pbkdf2_async,
+ crypto::op_node_sign,
winerror::op_node_sys_to_uv_error,
v8::op_v8_cached_data_version_tag,
v8::op_v8_get_heap_statistics,
@@ -406,7 +407,7 @@ pub fn initialize_runtime(
let source_code = format!(
r#"(function loadBuiltinNodeModules(nodeGlobalThisName, usesLocalNodeModulesDir, argv0) {{
Deno[Deno.internal].node.initialize(
- nodeGlobalThisName,
+ nodeGlobalThisName,
usesLocalNodeModulesDir,
argv0
);
diff --git a/ext/node/polyfills/internal/crypto/hash.ts b/ext/node/polyfills/internal/crypto/hash.ts
index 63c92190c..00dfa19af 100644
--- a/ext/node/polyfills/internal/crypto/hash.ts
+++ b/ext/node/polyfills/internal/crypto/hash.ts
@@ -73,7 +73,7 @@ export class Hash extends Transform {
if (typeof algorithm === "string") {
this.#context = ops.op_node_create_hash(
- algorithm,
+ algorithm.toLowerCase(),
);
if (this.#context === 0) {
throw new TypeError(`Unknown hash algorithm: ${algorithm}`);
diff --git a/ext/node/polyfills/internal/crypto/sig.ts b/ext/node/polyfills/internal/crypto/sig.ts
index d61f82b0e..e49128b1e 100644
--- a/ext/node/polyfills/internal/crypto/sig.ts
+++ b/ext/node/polyfills/internal/crypto/sig.ts
@@ -14,6 +14,12 @@ import type {
PublicKeyInput,
} from "ext:deno_node/internal/crypto/types.ts";
import { KeyObject } from "ext:deno_node/internal/crypto/keys.ts";
+import { createHash, Hash } from "ext:deno_node/internal/crypto/hash.ts";
+import { KeyFormat, KeyType } from "ext:deno_node/internal/crypto/types.ts";
+import { isArrayBufferView } from "ext:deno_node/internal/util/types.ts";
+
+const { core } = globalThis.__bootstrap;
+const { ops } = core;
export type DSAEncoding = "der" | "ieee-p1363";
@@ -37,30 +43,62 @@ export interface VerifyKeyObjectInput extends SigningOptions {
export type KeyLike = string | Buffer | KeyObject;
export class Sign extends Writable {
+ hash: Hash;
+ #digestType: string;
+
constructor(algorithm: string, _options?: WritableOptions) {
validateString(algorithm, "algorithm");
- super();
-
- notImplemented("crypto.Sign");
+ super({
+ write(chunk, enc, callback) {
+ this.update(chunk, enc);
+ callback();
+ },
+ });
+
+ algorithm = algorithm.toLowerCase();
+
+ if (algorithm.startsWith("rsa-")) {
+ // Allows RSA-[digest_algorithm] as a valid algorithm
+ algorithm = algorithm.slice(4);
+ }
+ this.#digestType = algorithm;
+ this.hash = createHash(this.#digestType);
}
- sign(privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput): Buffer;
sign(
privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
- outputFormat: BinaryToTextEncoding,
- ): string;
- sign(
- _privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
- _outputEncoding?: BinaryToTextEncoding,
+ encoding?: BinaryToTextEncoding,
): Buffer | string {
- notImplemented("crypto.Sign.prototype.sign");
+ let keyData: Uint8Array;
+ let keyType: KeyType;
+ let keyFormat: KeyFormat;
+ if (typeof privateKey === "string" || isArrayBufferView(privateKey)) {
+ // if the key is BinaryLike, interpret it as a PEM encoded RSA key
+ keyData = privateKey;
+ keyType = "rsa";
+ keyFormat = "pem";
+ } else {
+ // TODO(kt3k): Add support for the case when privateKey is a KeyObject,
+ // CryptoKey, etc
+ notImplemented("crypto.Sign.prototype.sign with non BinaryLike input");
+ }
+ const ret = Buffer.from(ops.op_node_sign(
+ this.hash.digest(),
+ this.#digestType,
+ keyData!,
+ keyType,
+ keyFormat,
+ ));
+ return encoding ? ret.toString(encoding) : ret;
}
- update(data: BinaryLike): this;
- update(data: string, inputEncoding: Encoding): this;
- update(_data: BinaryLike | string, _inputEncoding?: Encoding): this {
- notImplemented("crypto.Sign.prototype.update");
+ update(
+ data: BinaryLike | string,
+ encoding?: Encoding,
+ ): this {
+ this.hash.update(data, encoding);
+ return this;
}
}