Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(runtime): support RSA-PSS, RSASSA-PKCS1-v1_5 & ECDSA for SubtleCrypto#sign & SubtleCrypto#verify #861

Merged
merged 11 commits into from
May 14, 2023
9 changes: 9 additions & 0 deletions .changeset/swift-rocks-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@lagon/cli': patch
'@lagon/runtime': patch
'@lagon/serverless': patch
'@lagon/docs': patch
'@lagon/js-runtime': patch
---

Add RSA-PSS, RSASSA-PKCS1-v1_5 & ECDSA to `SubtleCrypto#sign` & `SubtleCrypto#verify`
79 changes: 77 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ members = [
lto = "thin"
codegen-units = 1
panic = "abort"

[profile.dev.package.num-bigint-dig]
opt-level = 3
166 changes: 158 additions & 8 deletions crates/runtime/tests/crypto.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::time::Duration;

use lagon_runtime_http::{Request, Response, RunResult};
use lagon_runtime_isolate::options::IsolateOptions;

Expand Down Expand Up @@ -478,31 +480,50 @@ async fn crypto_ecdh_derive_bits() {
utils::setup();
let (send, receiver) = utils::create_isolate(IsolateOptions::new(
"export async function handler() {
const keypair = await crypto.subtle.generateKey(
const keypair_1 = await crypto.subtle.generateKey(
{
name: 'ECDH',
namedCurve: 'P-384',
namedCurve: 'P-256',
},
true,
['deriveBits', 'deriveKey'],
);
const result = await crypto.subtle.deriveBits(
const result_1 = await crypto.subtle.deriveBits(
{
name: 'ECDH',
public: keypair.publicKey,
namedCurve: 'P-256',
public: keypair_1.publicKey,
},
keypair.privateKey,
keypair_1.privateKey,
256,
);
return new Response(`${result.byteLength * 8}`);

const keypair_2 = await crypto.subtle.generateKey(
{
name: 'ECDH',
namedCurve: 'P-384',
},
true,
['deriveBits', 'deriveKey'],
);
const result_2 = await crypto.subtle.deriveBits(
{
name: 'ECDH',
namedCurve: 'P-384',
public: keypair_2.publicKey,
},
keypair_2.privateKey,
384,
);
return new Response(`${result_1.byteLength * 8} ${result_2.byteLength * 8}`);
}"
.into(),
));
send(Request::default());

assert_eq!(
receiver.recv_async().await.unwrap().as_response(),
Response::from("256")
Response::from("256 384")
);
}

Expand All @@ -521,7 +542,6 @@ async fn crypto_derive_key() {
);

const salt = await crypto.getRandomValues(new Uint8Array(16));

const derivedKey = await crypto.subtle.deriveKey(
{
name: 'PBKDF2',
Expand All @@ -548,3 +568,133 @@ async fn crypto_derive_key() {
Response::from("true true true true true")
);
}

#[tokio::test]
async fn crypto_ecdsa_sign_verify() {
utils::setup();
let (send, receiver) = utils::create_isolate(IsolateOptions::new(
"export async function handler() {
const keypair_1 = await crypto.subtle.generateKey(
{
name: 'ECDSA',
namedCurve: 'P-384',
},
true,
['sign', 'verified'],
);

const data = new Uint8Array([1, 2, 3]);
const signAlgorithm = { name: 'ECDSA', hash: 'SHA-384' };
const signature = await crypto.subtle.sign(
signAlgorithm,
keypair_1.privateKey,
data,
);

const verified = await crypto.subtle.verify(
signAlgorithm,
keypair_1.publicKey,
signature,
data,
);
return new Response(`${verified}`);
}"
.into(),
));
send(Request::default());

assert_eq!(
receiver.recv_async().await.unwrap().as_response(),
Response::from("true")
);
}

#[tokio::test]
async fn crypto_rsa_pss_sign_verify() {
utils::setup();
let (send, receiver) = utils::create_isolate(
IsolateOptions::new(
"export async function handler() {
const keypair = await crypto.subtle.generateKey(
{
name: 'RSA-PSS',
modulusLength: 1024,
publicExponent: new Uint8Array([1, 0, 1]),
},
true,
['sign', 'verify'],
);

const data = new Uint8Array([1, 2, 3]);
const signAlgorithm = { name: 'RSA-PSS', saltLength: 32 };
const signature = await crypto.subtle.sign(
signAlgorithm,
keypair.privateKey,
data,
);

const verified = await crypto.subtle.verify(
signAlgorithm,
keypair.publicKey,
signature,
data,
);
return new Response(`${verified}`);
}"
.into(),
)
.tick_timeout(Duration::from_secs(5))
.total_timeout(Duration::from_secs(10)),
);
send(Request::default());

assert_eq!(
receiver.recv_async().await.unwrap().as_response(),
Response::from("true")
);
}

#[tokio::test]
async fn crypto_rsa_ssa_sign_verify() {
utils::setup();
let (send, receiver) = utils::create_isolate(
IsolateOptions::new(
"export async function handler() {
const keypair = await crypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 1024,
publicExponent: new Uint8Array([1, 0, 1]),
},
true,
['sign', 'verify'],
);

const data = new Uint8Array([1, 2, 3]);
const signAlgorithm = { name: 'RSASSA-PKCS1-v1_5', saltLength: 32 };
const signature = await crypto.subtle.sign(
signAlgorithm,
keypair.privateKey,
data,
);

const verified = await crypto.subtle.verify(
signAlgorithm,
keypair.publicKey,
signature,
data,
);
return new Response(`${verified}`);
}"
.into(),
)
.tick_timeout(Duration::from_secs(5))
.total_timeout(Duration::from_secs(10)),
);
send(Request::default());

assert_eq!(
receiver.recv_async().await.unwrap().as_response(),
Response::from("true")
);
}
3 changes: 3 additions & 0 deletions crates/runtime_crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ aes = "0.8.2"
aes-gcm = "0.10.1"
cbc = { version = "0.1.2", features = ["std"] }
ring = { version = "0.16.20", features = ["std"] }
once_cell = "1.17.1"
num-traits = "0.2.15"
rsa = { version = "=0.9.2", default-features = false, features = ["std", "sha2"] }
p256 = { version = "0.13.2", features = ["ecdh"] }
p384 = "0.13.0"
Loading