From 4b387bb77f33fb39fde8f63a22820a5ac093f51d Mon Sep 17 00:00:00 2001 From: aniqaqill Date: Thu, 23 Jan 2025 23:43:07 +0800 Subject: [PATCH] qrefactor crypto_test.go againts web platform tests --- .../modules/k6/webcrypto/tests/crypto_test.go | 358 +++++++----------- .../k6/webcrypto/tests/subtle_crypto_test.go | 2 - .../k6/webcrypto/tests/test_setup_test.go | 3 + ...oAPI__derive_bits_keys__ecdh_bits.js.patch | 2 +- ..._encrypt_decrypt__aes_gcm_vectors.js.patch | 2 +- ...bCryptoAPI__generateKey__failures.js.patch | 2 +- ...CryptoAPI__generateKey__successes.js.patch | 2 +- ...rt_export__ec_importKey.https.any.js.patch | 2 +- ...t_export__rsa_importKey.https.any.js.patch | 2 +- ...rt__symmetric_importKey.https.any.js.patch | 2 +- ...toAPI__sign_verify__ecdsa_vectors.js.patch | 2 +- .../WebCryptoAPI__sign_verify__rsa.js.patch | 2 +- 12 files changed, 146 insertions(+), 235 deletions(-) diff --git a/internal/js/modules/k6/webcrypto/tests/crypto_test.go b/internal/js/modules/k6/webcrypto/tests/crypto_test.go index 6de1cf70419..03f8c0f69d6 100644 --- a/internal/js/modules/k6/webcrypto/tests/crypto_test.go +++ b/internal/js/modules/k6/webcrypto/tests/crypto_test.go @@ -3,267 +3,177 @@ package tests import ( - "fmt" + "os" + "strings" "testing" "github.com/stretchr/testify/assert" ) -func TestGetRandomValues(t *testing.T) { - t.Parallel() - - ts := newConfiguredRuntime(t) - - _, gotErr := ts.RunOnEventLoop(` - var input = new Uint8Array(10); - var output = crypto.getRandomValues(input); - - if (output.length != 10) { - throw new Error("output.length != 10"); - } - - // Note that we're comparing references here, not values. - // Thus we're testing that the same typed array is returned. - if (input !== output) { - throw new Error("input !== output"); - } - `) - - assert.NoError(t, gotErr) -} - -// TODO: Add tests for DataView - -// TestGetRandomValues tests that crypto.getRandomValues() supports the expected types -// listed in the [specification]: -// - Int8Array -// - Int16Arrays -// - Int32Array -// - Uint8Array -// - Uint8ClampedArray -// - Uint16Array -// - Uint32Array -// -// It stands as the k6 counterpart of the [official test suite] on that topic. +// TestCryptoWebPlatformTestSuite runs the Web Platform Tests for the Crypto interface. +// It ensures that the k6 implementation of the WebCrypto API is compliant with the specification. // -// [specification]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues -// [official test suite]: https://github.com/web-platform-tests/wpt/blob/master/WebCryptoAPI/getRandomValues.any.js#L1 -func TestGetRandomValuesSupportedTypedArrays(t *testing.T) { +// The tests are loaded from the Web Platform Tests repository and executed in the k6 runtime. +// Any differences between the k6 implementation and the specification are documented in patches. +func TestCryptoWebPlatformTestSuite(t *testing.T) { t.Parallel() - ts := newConfiguredRuntime(t) - - type testCase struct { - name string - typedArray string - wantErr bool + // Check if the test is running in the correct environment + info, err := os.Stat(webPlatformTestSuite) + if os.IsNotExist(err) || err != nil || !info.IsDir() { + t.Fatalf( + "The Web Platform Test directory does not exist, err: %s. Please check webcrypto/tests/README.md how to setup it", + err, + ) } - testCases := []testCase{ + // Define the test cases for the Crypto interface + tests := []struct { + catalog string // Subdirectory in the WPT repository + files []string // List of test files to execute + callFn string // Function to call after executing the test files (e.g., "run_test") + }{ + // what test i shoudl done? { - name: "filling a Int8Array typed array with random values should succeed", - typedArray: "Int8Array", - wantErr: false, + catalog: "digest", + files: []string{ + "digest.https.any.js", + }, }, { - name: "filling a Int16Array typed array with random values should succeed", - typedArray: "Int16Array", - wantErr: false, + catalog: "generateKey", + files: []string{ + "successes.js", + }, + callFn: "run_test", }, { - name: "filling a Int32Array typed array with random values should succeed", - typedArray: "Int32Array", - wantErr: false, + catalog: "generateKey", + files: []string{ + "failures.js", + }, + callFn: "run_test", }, { - name: "filling a Uint8Array typed array with random values should succeed", - typedArray: "Uint8Array", - wantErr: false, + catalog: "import_export", + files: []string{ + "symmetric_importKey.https.any.js", + }, }, { - name: "filling a Uint8ClampedArray typed array with random values should succeed", - typedArray: "Uint8ClampedArray", - wantErr: false, + catalog: "import_export", + files: []string{ + "ec_importKey.https.any.js", + }, }, { - name: "filling a Uint16Array typed array with random values should succeed", - typedArray: "Uint16Array", - wantErr: false, + catalog: "import_export", + files: []string{ + "rsa_importKey.https.any.js", + }, }, { - name: "filling a Uint32Array typed array with random values should succeed", - typedArray: "Uint32Array", - wantErr: false, + catalog: "encrypt_decrypt", + files: []string{ + "aes_cbc_vectors.js", + "aes.js", + }, + callFn: "run_test", }, - - // Unsupported typed arrays { - name: "filling a BigInt64Array typed array with random values should succeed", - typedArray: "BigInt64Array", - wantErr: true, + catalog: "encrypt_decrypt", + files: []string{ + "aes_ctr_vectors.js", + "aes.js", + }, + callFn: "run_test", }, { - name: "filling a BigUint64Array typed array with random values should succeed", - typedArray: "BigUint64Array", - wantErr: true, + // Note @oleiade: although the specification targets support + // for various iv sizes, go AES GCM cipher only supports 96bits. + // Thus, although the official WebPlatform test suite contains + // vectors for various iv sizes, we only test the 96bits one. + catalog: "encrypt_decrypt", + files: []string{ + "aes_gcm_96_iv_fixtures.js", + "aes_gcm_vectors.js", + "aes.js", + }, + callFn: "run_test", }, { - name: "filling a Float32Array typed array with random values should fail", - typedArray: "Float32Array", - wantErr: true, + // RSA-OAEP + catalog: "encrypt_decrypt", + files: []string{ + "rsa_vectors.js", + "rsa.js", + }, + callFn: "run_test", }, { - name: "filling a Float64Array typed array with random values should fail", - typedArray: "Float64Array", - wantErr: true, + catalog: "sign_verify", + files: []string{ + "hmac_vectors.js", "hmac.js", + }, + callFn: "run_test", + }, + { + catalog: "sign_verify", + files: []string{ + "ecdsa_vectors.js", + "ecdsa.js", + }, + callFn: "run_test", + }, + { + catalog: "sign_verify", + files: []string{ + "rsa_pss_vectors.js", + "rsa.js", + }, + callFn: "run_test", + }, + { + catalog: "sign_verify", + files: []string{ + "rsa_pss_vectors.js", "rsa.js", + }, + callFn: "run_test", + }, + { + catalog: "derive_bits_keys", + files: []string{ + "ecdh_bits.js", + }, + callFn: "define_tests", }, } - for _, tc := range testCases { - _, gotErr := ts.RunOnEventLoop(fmt.Sprintf(` - var buf = new %s(10); - crypto.getRandomValues(buf); - - if (buf.length != 10) { - throw new Error("buf.length != 10"); - } - `, tc.typedArray)) - - if tc.wantErr != (gotErr != nil) { - t.Fatalf("unexpected error: %v", gotErr) - } - - assert.Equal(t, tc.wantErr, gotErr != nil, tc.name) - } -} - -// TestGetRandomValuesQuotaExceeded tests that crypto.getRandomValues() returns a -// QuotaExceededError when the requested size is too large. As described in the -// [specification], the maximum size is 65536 bytes. -// -// It stands as the k6 counterpart of the [official test suite] on that topic. -// -// [specification]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues -// [official test suite]: https://github.com/web-platform-tests/wpt/blob/master/WebCryptoAPI/getRandomValues.any.js#L1 -func TestGetRandomValuesQuotaExceeded(t *testing.T) { - t.Parallel() + // Run each test case + for _, tt := range tests { + tt := tt + testName := tt.catalog + "/" + strings.Join(tt.files, "_") - ts := newConfiguredRuntime(t) + t.Run(testName, func(t *testing.T) { + t.Parallel() - _, gotErr := ts.RunOnEventLoop(` - var buf = new Uint8Array(1000000000); - crypto.getRandomValues(buf); - `) + ts := newConfiguredRuntime(t) - assert.Error(t, gotErr) - assert.Contains(t, gotErr.Error(), "QuotaExceededError") -} - -// TestRandomUUIDIsTheNamespaceFormat tests that the UUID generated by -// crypto.randomUUID() is in the correct format. -// -// It stands as the k6 counterpart of the equivalent [WPT test]. -// -// [WPT test]: https://github.com/web-platform-tests/wpt/blob/master/WebCryptoAPI/randomUUID.https.any.js#L16 -func TestRandomUUIDIsInTheNamespaceFormat(t *testing.T) { - t.Parallel() - - ts := newConfiguredRuntime(t) - - _, gotErr := ts.RunOnEventLoop(` - const iterations = 256; - const uuids = new Set(); - - function randomUUID() { - const uuid = crypto.randomUUID(); - if (uuids.has(uuid)) { - throw new Error("UUID collision: " + uuid); - } - uuids.add(uuid); - return uuid - } - - const UUIDRegex = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/ - for (let i = 0; i < iterations; i++) { - // Assert that the UUID is in the correct format and - // that it is unique. - UUIDRegex.test(randomUUID()); - } - `) - - assert.NoError(t, gotErr) -} - -// TestRandomUUIDIVersion tests that the UUID generated by -// crypto.randomUUID() has the correct version 4 bits set -// (4 most significant bits of the bytes[6] set to `0100`). -// -// It stands as the k6 counterpart of the equivalent [WPT test]. -// -// [WPT test]: https://github.com/web-platform-tests/wpt/blob/master/WebCryptoAPI/randomUUID.https.any.js#L25 -func TestRandomUUIDVersion(t *testing.T) { - t.Parallel() - - ts := newConfiguredRuntime(t) - - _, gotErr := ts.RunOnEventLoop(` - const iterations = 256; - const uuids = new Set(); - - function randomUUID() { - const uuid = crypto.randomUUID(); - if (uuids.has(uuid)) { - throw new Error("UUID collision: " + uuid); - } - uuids.add(uuid); - return uuid - } - - for (let i = 0; i < iterations; i++) { - let value = parseInt(randomUUID().split('-')[2].slice(0, 2), 16) - value &= 0b11110000 - if (value !== 0b01000000) { - throw new Error("UUID version is not 4: " + value); - } - } - `) - - assert.NoError(t, gotErr) -} - -// TestRandomUUIDIVariant tests that the UUID generated by -// crypto.randomUUID() has the correct variant 2 bits set -// (2 most significant bits of the bytes[8] set to `10`). -// -// It stands as the k6 counterpart of the equivalent [WPT test]. -// -// [WPT test]: https://github.com/web-platform-tests/wpt/blob/master/WebCryptoAPI/randomUUID.https.any.js#L35 -func TestRandomUUIDVariant(t *testing.T) { - t.Parallel() - - ts := newConfiguredRuntime(t) - - _, gotErr := ts.RunOnEventLoop(` - const iterations = 256; - const uuids = new Set(); - - function randomUUID() { - const uuid = crypto.randomUUID(); - if (uuids.has(uuid)) { - throw new Error("UUID collision: " + uuid); - } - uuids.add(uuid); - return uuid - } + gotErr := ts.EventLoop.Start(func() error { + // Execute the test files + for _, script := range tt.files { + compileAndRun(t, ts, webPlatformTestSuite+tt.catalog, script) + } - for (let i = 0; i < iterations; i++) { - let value = parseInt(randomUUID().split('-')[3].slice(0, 2), 16) - value &= 0b11000000 - if (value !== 0b10000000) { - throw new Error("UUID variant is not 1: " + value); - } - } - `) + // Call the specified function (e.g., "run_test") if provided + if tt.callFn == "" { + return nil + } - assert.NoError(t, gotErr) + _, err := ts.VU.Runtime().RunString(tt.callFn + `()`) + return err + }) + assert.NoError(t, gotErr) + }) + } } diff --git a/internal/js/modules/k6/webcrypto/tests/subtle_crypto_test.go b/internal/js/modules/k6/webcrypto/tests/subtle_crypto_test.go index 13dc8e7f295..1f647e82385 100644 --- a/internal/js/modules/k6/webcrypto/tests/subtle_crypto_test.go +++ b/internal/js/modules/k6/webcrypto/tests/subtle_crypto_test.go @@ -11,8 +11,6 @@ import ( "github.com/stretchr/testify/assert" ) -const webPlatformTestSuite = "./wpt/WebCryptoAPI/" - func TestWebPlatformTestSuite(t *testing.T) { t.Parallel() diff --git a/internal/js/modules/k6/webcrypto/tests/test_setup_test.go b/internal/js/modules/k6/webcrypto/tests/test_setup_test.go index 2abab430dec..dfc2ddd26f3 100644 --- a/internal/js/modules/k6/webcrypto/tests/test_setup_test.go +++ b/internal/js/modules/k6/webcrypto/tests/test_setup_test.go @@ -13,6 +13,8 @@ import ( "github.com/stretchr/testify/require" ) +const webPlatformTestSuite = "./wpt/WebCryptoAPI/" + const initGlobals = ` globalThis.CryptoKey = require("k6/x/webcrypto").CryptoKey; ` @@ -61,6 +63,7 @@ func newConfiguredRuntime(t testing.TB) *modulestest.Runtime { return rt } +// compileAndRun compiles a JavaScript file into a sobek.Program and runs it in the runtime. func compileAndRun(t testing.TB, runtime *modulestest.Runtime, base, file string) { program, err := modulestest.CompileFile(base, file) require.NoError(t, err) diff --git a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__derive_bits_keys__ecdh_bits.js.patch b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__derive_bits_keys__ecdh_bits.js.patch index f687786289a..9210fa9b0bf 100644 --- a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__derive_bits_keys__ecdh_bits.js.patch +++ b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__derive_bits_keys__ecdh_bits.js.patch @@ -1,5 +1,5 @@ diff --git a/WebCryptoAPI/derive_bits_keys/ecdh_bits.js b/WebCryptoAPI/derive_bits_keys/ecdh_bits.js -index 36b29c20a..c9c413599 100644 +index 36b29c20a2..c9c413599f 100644 --- a/WebCryptoAPI/derive_bits_keys/ecdh_bits.js +++ b/WebCryptoAPI/derive_bits_keys/ecdh_bits.js @@ -65,15 +65,17 @@ function define_tests() { diff --git a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__encrypt_decrypt__aes_gcm_vectors.js.patch b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__encrypt_decrypt__aes_gcm_vectors.js.patch index f998511db14..6a67662bcd0 100644 --- a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__encrypt_decrypt__aes_gcm_vectors.js.patch +++ b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__encrypt_decrypt__aes_gcm_vectors.js.patch @@ -1,5 +1,5 @@ diff --git a/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js b/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js -index 965fe9564..0364b93cd 100644 +index 965fe9564d..0364b93cd9 100644 --- a/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js +++ b/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js @@ -22,7 +22,10 @@ function getTestVectors() { diff --git a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__failures.js.patch b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__failures.js.patch index 201d5f94cf2..94539b7fc50 100644 --- a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__failures.js.patch +++ b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__failures.js.patch @@ -1,5 +1,5 @@ diff --git a/WebCryptoAPI/generateKey/failures.js b/WebCryptoAPI/generateKey/failures.js -index e0f0279a6..61495ca75 100644 +index e0f0279a69..61495ca75e 100644 --- a/WebCryptoAPI/generateKey/failures.js +++ b/WebCryptoAPI/generateKey/failures.js @@ -32,10 +32,10 @@ function run_test(algorithmNames) { diff --git a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__successes.js.patch b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__successes.js.patch index 50d839c0aab..3f3b2239666 100644 --- a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__successes.js.patch +++ b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__successes.js.patch @@ -1,5 +1,5 @@ diff --git a/WebCryptoAPI/generateKey/successes.js b/WebCryptoAPI/generateKey/successes.js -index a9a168e1a..88861ab87 100644 +index a9a168e1ad..88861ab87f 100644 --- a/WebCryptoAPI/generateKey/successes.js +++ b/WebCryptoAPI/generateKey/successes.js @@ -21,17 +21,17 @@ function run_test(algorithmNames, slowTest) { diff --git a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__ec_importKey.https.any.js.patch b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__ec_importKey.https.any.js.patch index 0035c0ea7d0..1b7c93376e4 100644 --- a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__ec_importKey.https.any.js.patch +++ b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__ec_importKey.https.any.js.patch @@ -1,5 +1,5 @@ diff --git a/WebCryptoAPI/import_export/ec_importKey.https.any.js b/WebCryptoAPI/import_export/ec_importKey.https.any.js -index a01bfbb0e..4b7ac8cf0 100644 +index a01bfbb0ef..4b7ac8cf05 100644 --- a/WebCryptoAPI/import_export/ec_importKey.https.any.js +++ b/WebCryptoAPI/import_export/ec_importKey.https.any.js @@ -72,7 +72,8 @@ diff --git a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__rsa_importKey.https.any.js.patch b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__rsa_importKey.https.any.js.patch index 3d3fb5f877e..c6738bef41e 100644 --- a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__rsa_importKey.https.any.js.patch +++ b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__rsa_importKey.https.any.js.patch @@ -1,5 +1,5 @@ diff --git a/WebCryptoAPI/import_export/rsa_importKey.https.any.js b/WebCryptoAPI/import_export/rsa_importKey.https.any.js -index c0917cab6..93d16cfc4 100644 +index c0917cab68..93d16cfc41 100644 --- a/WebCryptoAPI/import_export/rsa_importKey.https.any.js +++ b/WebCryptoAPI/import_export/rsa_importKey.https.any.js @@ -113,7 +113,8 @@ diff --git a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__symmetric_importKey.https.any.js.patch b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__symmetric_importKey.https.any.js.patch index 6cfb0c1d821..f53c06a0ac5 100644 --- a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__symmetric_importKey.https.any.js.patch +++ b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__symmetric_importKey.https.any.js.patch @@ -1,5 +1,5 @@ diff --git a/WebCryptoAPI/import_export/symmetric_importKey.https.any.js b/WebCryptoAPI/import_export/symmetric_importKey.https.any.js -index 01b318018..7957cb204 100644 +index 01b3180189..7957cb204b 100644 --- a/WebCryptoAPI/import_export/symmetric_importKey.https.any.js +++ b/WebCryptoAPI/import_export/symmetric_importKey.https.any.js @@ -18,16 +18,17 @@ diff --git a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__ecdsa_vectors.js.patch b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__ecdsa_vectors.js.patch index 65247db3e38..29ed98bd924 100644 --- a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__ecdsa_vectors.js.patch +++ b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__ecdsa_vectors.js.patch @@ -1,5 +1,5 @@ diff --git a/WebCryptoAPI/sign_verify/ecdsa_vectors.js b/WebCryptoAPI/sign_verify/ecdsa_vectors.js -index aa9b81ba8..185c82622 100644 +index aa9b81ba8a..185c826220 100644 --- a/WebCryptoAPI/sign_verify/ecdsa_vectors.js +++ b/WebCryptoAPI/sign_verify/ecdsa_vectors.js @@ -90,7 +90,9 @@ function getInvalidTestVectors() { diff --git a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__rsa.js.patch b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__rsa.js.patch index 7c20fed5ea0..dfc281a77ba 100644 --- a/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__rsa.js.patch +++ b/internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__rsa.js.patch @@ -1,5 +1,5 @@ diff --git a/WebCryptoAPI/sign_verify/rsa.js b/WebCryptoAPI/sign_verify/rsa.js -index 5abadd3d4..6076bd7de 100644 +index 5abadd3d4b..6076bd7deb 100644 --- a/WebCryptoAPI/sign_verify/rsa.js +++ b/WebCryptoAPI/sign_verify/rsa.js @@ -156,7 +156,9 @@ function run_test() {