From 9a57b442cb09a36b2cc85e436da2265ae8a1ded6 Mon Sep 17 00:00:00 2001 From: HamdaanAliQuatil Date: Sun, 16 Jun 2024 13:15:43 +0530 Subject: [PATCH 1/2] test: add tests for importKeyException --- lib/src/testing/utils/testrunner.dart | 64 +++++++++++++++++++++------ lib/src/testing/webcrypto/ecdh.dart | 30 +++++++++++++ 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/lib/src/testing/utils/testrunner.dart b/lib/src/testing/utils/testrunner.dart index 6aed509a..011bbe8f 100644 --- a/lib/src/testing/utils/testrunner.dart +++ b/lib/src/testing/utils/testrunner.dart @@ -63,6 +63,9 @@ class _TestCase { // Parameters for key import (always required) final Map? importKeyParams; + // Parameters for import key exception (optional, if there is an exception) + final Map? importKeyException; + // Parameters for sign/verify (required, if there is a signature) final Map? signVerifyParams; @@ -72,6 +75,20 @@ class _TestCase { // Parameters for deriveBits (required, if there is a derivedBits) final Map? deriveParams; + String? get pkcs8ImportKeyException { + if (importKeyException != null) { + return importKeyException?['pkcs8Exception']; + } + return null; + } + + String? get jwkImportKeyException { + if (importKeyException != null) { + return importKeyException?['jwkException']; + } + return null; + } + _TestCase( this.name, { this.generateKeyParams, @@ -90,6 +107,7 @@ class _TestCase { this.signVerifyParams, this.encryptDecryptParams, this.deriveParams, + this.importKeyException, }); factory _TestCase.fromJson(Map json) { @@ -110,6 +128,7 @@ class _TestCase { derivedBits: _optionalBase64Decode(json['derivedBits']), derivedLength: json['derivedLength'] as int?, importKeyParams: _optionalStringMapDecode(json['importKeyParams']), + importKeyException: _optionalStringMapDecode(json['importKeyException']), signVerifyParams: _optionalStringMapDecode(json['signVerifyParams']), encryptDecryptParams: _optionalStringMapDecode(json['encryptDecryptParams']), @@ -746,6 +765,23 @@ void _runTests( publicKey = pair.publicKey; privateKey = pair.privateKey; }); + } else if (c.importKeyException != null) { + test('pkcs8 import exception', () async { + try { + await r._importPrivatePkcs8Key!(c.privatePkcs8KeyData!, {'curve': 'p-521'}); + check(false, 'Expected an exception for P-512 import'); + } catch (e) { + check(e.toString().contains(c.pkcs8ImportKeyException!)); + } + }); + test('jwk import exception', () async { + try { + await r._importPrivateJsonWebKey!(c.privateJsonWebKeyData!, {'curve': 'p-521'}); + check(false, 'Expected an exception for P-512 import'); + } catch (e) { + check(e.toString().contains(c.jwkImportKeyException!)); + } + }); } else { test('import key-pair', () async { // Get a privateKey @@ -876,7 +912,8 @@ void _runTests( }); } - test('validated derivedBits', () async { + if (c.pkcs8ImportKeyException == null){ + test('validated derivedBits', () async { final derived = await r._deriveBits( _KeyPair( privateKey: privateKey as PrivateKey, @@ -889,6 +926,7 @@ void _runTests( 'failed to derivedBits are not consistent', ); }); + } } //------------------------------ Utilities for testing @@ -1021,7 +1059,7 @@ void _runTests( //------------------------------ Test import public key - if (c.publicRawKeyData != null) { + if (c.publicRawKeyData != null && c.pkcs8ImportKeyException == null) { assert(!r._isSymmetric && r._importPublicRawKey != null); test('importPublicRawKey()', () async { @@ -1033,7 +1071,7 @@ void _runTests( }); } - if (c.publicSpkiKeyData != null) { + if (c.publicSpkiKeyData != null && c.pkcs8ImportKeyException == null) { assert(!r._isSymmetric && r._importPublicSpkiKey != null); test('importPublicSpkiKey()', () async { @@ -1045,7 +1083,7 @@ void _runTests( }); } - if (c.publicJsonWebKeyData != null) { + if (c.publicJsonWebKeyData != null && c.jwkImportKeyException == null) { assert(!r._isSymmetric && r._importPublicJsonWebKey != null); test('importPublicJsonWebKey()', () async { @@ -1069,7 +1107,7 @@ void _runTests( }); } - if (c.privatePkcs8KeyData != null) { + if (c.privatePkcs8KeyData != null && c.pkcs8ImportKeyException == null) { test('importPrivatePkcs8Key()', () async { final key = await r._importPrivatePkcs8Key!( c.privatePkcs8KeyData!, @@ -1079,7 +1117,7 @@ void _runTests( }); } - if (c.privateJsonWebKeyData != null) { + if (c.privateJsonWebKeyData != null && c.jwkImportKeyException == null) { test('importPrivateJsonWebKey()', () async { final key = await r._importPrivateJsonWebKey!( c.privateJsonWebKeyData!, @@ -1360,7 +1398,7 @@ void _runTests( } //------------------------------ Test derivedBits - if (r._deriveBits != null) { + if (r._deriveBits != null && (c.pkcs8ImportKeyException == null || c.jwkImportKeyException == null)) { test('deriveBits', () async { final derived = await r._deriveBits( _KeyPair( @@ -1374,7 +1412,7 @@ void _runTests( } //------------------------------ export/import private key - if (r._exportPrivateRawKey != null) { + if (r._exportPrivateRawKey != null && (c.pkcs8ImportKeyException == null || c.jwkImportKeyException == null)) { test('export/import raw private key', () async { final keyData = await r._exportPrivateRawKey(privateKey as PrivateKey); check(keyData.isNotEmpty, 'exported key is empty'); @@ -1384,7 +1422,7 @@ void _runTests( }); } - if (r._exportPrivatePkcs8Key != null) { + if (r._exportPrivatePkcs8Key != null && c.pkcs8ImportKeyException == null) { test('export/import pkcs8 private key', () async { final keyData = await r._exportPrivatePkcs8Key(privateKey as PrivateKey); check(keyData.isNotEmpty, 'exported key is empty'); @@ -1394,7 +1432,7 @@ void _runTests( }); } - if (r._exportPrivateJsonWebKey != null) { + if (r._exportPrivateJsonWebKey != null && c.jwkImportKeyException == null) { test('export/import jwk private key', () async { final jwk = await r._exportPrivateJsonWebKey(privateKey as PrivateKey); check(jwk.isNotEmpty, 'exported key is empty'); @@ -1406,7 +1444,7 @@ void _runTests( //------------------------------ export/import public key - if (r._exportPublicRawKey != null) { + if (r._exportPublicRawKey != null && (c.pkcs8ImportKeyException == null || c.jwkImportKeyException == null)) { assert(!r._isSymmetric && r._importPublicRawKey != null); test('export/import raw public key', () async { @@ -1418,7 +1456,7 @@ void _runTests( }); } - if (r._exportPublicSpkiKey != null) { + if (r._exportPublicSpkiKey != null && c.pkcs8ImportKeyException == null) { assert(!r._isSymmetric && r._importPublicSpkiKey != null); test('export/import pkcs8 public key', () async { @@ -1430,7 +1468,7 @@ void _runTests( }); } - if (r._exportPublicJsonWebKey != null) { + if (r._exportPublicJsonWebKey != null && c.jwkImportKeyException == null) { assert(!r._isSymmetric && r._importPublicJsonWebKey != null); test('export/import jwk public key', () async { diff --git a/lib/src/testing/webcrypto/ecdh.dart b/lib/src/testing/webcrypto/ecdh.dart index 2d3c18ac..76d87197 100644 --- a/lib/src/testing/webcrypto/ecdh.dart +++ b/lib/src/testing/webcrypto/ecdh.dart @@ -111,6 +111,36 @@ final _testData = [ "importKeyParams": {"curve": "p-256"}, "deriveParams": {} }, + { + "name": "generated on boringssl/linux (import key exception) at 2020-01-22T23:24:34", + "privatePkcs8KeyData": + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3aTiZ7odKAODYk4BpZlzulBCB/BptmxjtvrzyXI71UyhRANCAATl0GVa8O1sXXf2NV5qGJ/9/Vq8PVWCZuezADa1F0Vr2TaB8BseZIW+rhmEmLC2FfCdxj9NmLp00SilRTm40Hxm", + "privateJsonWebKeyData": { + "kty": "EC", + "crv": "P-256", + "x": "5dBlWvDtbF139jVeahif_f1avD1VgmbnswA2tRdFa9k", + "y": "NoHwGx5khb6uGYSYsLYV8J3GP02YunTRKKVFObjQfGY", + "d": "3aTiZ7odKAODYk4BpZlzulBCB_BptmxjtvrzyXI71Uw" + }, + "publicRawKeyData": + "BHiIXxrwhM92v4ueDrj3x1JJY4uS+II/IJPjqMvaKj/QfoOllnEkrnaOW1owBYRBMnP0pPouPkqbVfPACMUsfKs=", + "publicSpkiKeyData": + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeIhfGvCEz3a/i54OuPfHUklji5L4gj8gk+Ooy9oqP9B+g6WWcSSudo5bWjAFhEEyc/Sk+i4+SptV88AIxSx8qw==", + "publicJsonWebKeyData": { + "kty": "EC", + "crv": "P-256", + "x": "eIhfGvCEz3a_i54OuPfHUklji5L4gj8gk-Ooy9oqP9A", + "y": "foOllnEkrnaOW1owBYRBMnP0pPouPkqbVfPACMUsfKs" + }, + "derivedBits": "WA==", + "derivedLength": 7, + "importKeyParams": {"curve": "p-256"}, + "importKeyException": { + "pkcs8Exception": "FormatException: incorrect elliptic curve", + "jwkException": "JWK property \"crv\" is not" + }, + "deriveParams": {} + }, { "name": "generated on chrome/linux at 2020-01-22T23:24:39", "privatePkcs8KeyData": From 440bcdecffb83c57e38d407f7e91c47d2e2ffaa4 Mon Sep 17 00:00:00 2001 From: HamdaanAliQuatil Date: Mon, 15 Jul 2024 06:55:51 +0530 Subject: [PATCH 2/2] test: add validation for importKeyException --- lib/src/testing/utils/testrunner.dart | 120 +++++++++++++++----------- lib/src/testing/webcrypto/ecdh.dart | 19 ++-- 2 files changed, 81 insertions(+), 58 deletions(-) diff --git a/lib/src/testing/utils/testrunner.dart b/lib/src/testing/utils/testrunner.dart index 011bbe8f..f61dee65 100644 --- a/lib/src/testing/utils/testrunner.dart +++ b/lib/src/testing/utils/testrunner.dart @@ -63,8 +63,9 @@ class _TestCase { // Parameters for key import (always required) final Map? importKeyParams; - // Parameters for import key exception (optional, if there is an exception) - final Map? importKeyException; + // If not `null`, then importing private or public key MUST throw + // an exception that contains this string. + final String? importKeyException; // Parameters for sign/verify (required, if there is a signature) final Map? signVerifyParams; @@ -75,20 +76,6 @@ class _TestCase { // Parameters for deriveBits (required, if there is a derivedBits) final Map? deriveParams; - String? get pkcs8ImportKeyException { - if (importKeyException != null) { - return importKeyException?['pkcs8Exception']; - } - return null; - } - - String? get jwkImportKeyException { - if (importKeyException != null) { - return importKeyException?['jwkException']; - } - return null; - } - _TestCase( this.name, { this.generateKeyParams, @@ -128,7 +115,7 @@ class _TestCase { derivedBits: _optionalBase64Decode(json['derivedBits']), derivedLength: json['derivedLength'] as int?, importKeyParams: _optionalStringMapDecode(json['importKeyParams']), - importKeyException: _optionalStringMapDecode(json['importKeyException']), + importKeyException: json['importKeyException'] as String?, signVerifyParams: _optionalStringMapDecode(json['signVerifyParams']), encryptDecryptParams: _optionalStringMapDecode(json['encryptDecryptParams']), @@ -710,7 +697,14 @@ void _validateTestCase( check(c.importKeyParams != null); check((c.signVerifyParams != null) == (r._signBytes != null)); check((c.encryptDecryptParams != null) == (r._encryptBytes != null)); - check((c.deriveParams != null) == (r._deriveBits != null)); + + if (c.deriveParams != null) { + check((c.deriveParams != null) == (r._deriveBits != null)); + + if (r._deriveBits != null) { + check(c.derivedLength != null); + } + } if (c.signature != null) { check(r._signBytes != null); } @@ -720,9 +714,6 @@ void _validateTestCase( if (c.derivedBits != null) { check(r._deriveBits != null); } - if (r._deriveBits != null) { - check(c.derivedLength != null); - } // Check that data matches the methods we have in the runner. check(r._importPrivateRawKey != null || c.privateRawKeyData == null); @@ -731,6 +722,30 @@ void _validateTestCase( check(r._importPublicRawKey != null || c.publicRawKeyData == null); check(r._importPublicSpkiKey != null || c.publicSpkiKeyData == null); check(r._importPublicJsonWebKey != null || c.publicJsonWebKeyData == null); + + if (c.generateKeyParams != null) { + check(c.importKeyException == null, + 'importKeyException must be null when generateKeyParams is provided'); + } + + if (c.importKeyException != null) { + check(c.plaintext == null, + 'plaintext must be null when importKeyException is provided'); + check(c.signature == null, + 'signature must be null when importKeyException is provided'); + check(c.ciphertext == null, + 'ciphertext must be null when importKeyException is provided'); + check(c.derivedBits == null, + 'derivedBits must be null when importKeyException is provided'); + check(c.derivedLength == null, + 'derivedLength must be null when importKeyException is provided'); + check(c.signVerifyParams == null, + 'signVerifyParams must be null when importKeyException is provided'); + check(c.encryptDecryptParams == null, + 'encryptDecryptParams must be null when importKeyException is provided'); + check(c.deriveParams == null, + 'deriveParams must be null when importKeyException is provided'); + } } void _runTests( @@ -766,22 +781,29 @@ void _runTests( privateKey = pair.privateKey; }); } else if (c.importKeyException != null) { - test('pkcs8 import exception', () async { - try { - await r._importPrivatePkcs8Key!(c.privatePkcs8KeyData!, {'curve': 'p-521'}); - check(false, 'Expected an exception for P-512 import'); - } catch (e) { - check(e.toString().contains(c.pkcs8ImportKeyException!)); + if (c.privatePkcs8KeyData != null) { + test('pkcs8 import exception', () async { + try { + await r._importPrivatePkcs8Key!( + c.privatePkcs8KeyData!, {'curve': 'p-521'}); + check(false, 'Expected an exception for P-512 import'); + } catch (e) { + check(e.toString().contains(c.importKeyException!)); + } + }); } - }); - test('jwk import exception', () async { - try { - await r._importPrivateJsonWebKey!(c.privateJsonWebKeyData!, {'curve': 'p-521'}); - check(false, 'Expected an exception for P-512 import'); - } catch (e) { - check(e.toString().contains(c.jwkImportKeyException!)); + if (c.privateJsonWebKeyData != null) { + test('jwk import exception', () async { + try { + await r._importPrivateJsonWebKey!( + c.privateJsonWebKeyData!, {'curve': 'p-521'}); + check(false, 'Expected an exception for P-512 import'); + } catch (e) { + check(e.toString().contains(c.importKeyException!)); + } + }); } - }); + return; } else { test('import key-pair', () async { // Get a privateKey @@ -912,8 +934,7 @@ void _runTests( }); } - if (c.pkcs8ImportKeyException == null){ - test('validated derivedBits', () async { + test('validated derivedBits', () async { final derived = await r._deriveBits( _KeyPair( privateKey: privateKey as PrivateKey, @@ -926,7 +947,6 @@ void _runTests( 'failed to derivedBits are not consistent', ); }); - } } //------------------------------ Utilities for testing @@ -1059,7 +1079,7 @@ void _runTests( //------------------------------ Test import public key - if (c.publicRawKeyData != null && c.pkcs8ImportKeyException == null) { + if (c.publicRawKeyData != null) { assert(!r._isSymmetric && r._importPublicRawKey != null); test('importPublicRawKey()', () async { @@ -1071,7 +1091,7 @@ void _runTests( }); } - if (c.publicSpkiKeyData != null && c.pkcs8ImportKeyException == null) { + if (c.publicSpkiKeyData != null) { assert(!r._isSymmetric && r._importPublicSpkiKey != null); test('importPublicSpkiKey()', () async { @@ -1083,7 +1103,7 @@ void _runTests( }); } - if (c.publicJsonWebKeyData != null && c.jwkImportKeyException == null) { + if (c.publicJsonWebKeyData != null) { assert(!r._isSymmetric && r._importPublicJsonWebKey != null); test('importPublicJsonWebKey()', () async { @@ -1107,7 +1127,7 @@ void _runTests( }); } - if (c.privatePkcs8KeyData != null && c.pkcs8ImportKeyException == null) { + if (c.privatePkcs8KeyData != null) { test('importPrivatePkcs8Key()', () async { final key = await r._importPrivatePkcs8Key!( c.privatePkcs8KeyData!, @@ -1117,7 +1137,7 @@ void _runTests( }); } - if (c.privateJsonWebKeyData != null && c.jwkImportKeyException == null) { + if (c.privateJsonWebKeyData != null) { test('importPrivateJsonWebKey()', () async { final key = await r._importPrivateJsonWebKey!( c.privateJsonWebKeyData!, @@ -1398,7 +1418,7 @@ void _runTests( } //------------------------------ Test derivedBits - if (r._deriveBits != null && (c.pkcs8ImportKeyException == null || c.jwkImportKeyException == null)) { + if (r._deriveBits != null) { test('deriveBits', () async { final derived = await r._deriveBits( _KeyPair( @@ -1412,7 +1432,7 @@ void _runTests( } //------------------------------ export/import private key - if (r._exportPrivateRawKey != null && (c.pkcs8ImportKeyException == null || c.jwkImportKeyException == null)) { + if (r._exportPrivateRawKey != null) { test('export/import raw private key', () async { final keyData = await r._exportPrivateRawKey(privateKey as PrivateKey); check(keyData.isNotEmpty, 'exported key is empty'); @@ -1422,7 +1442,7 @@ void _runTests( }); } - if (r._exportPrivatePkcs8Key != null && c.pkcs8ImportKeyException == null) { + if (r._exportPrivatePkcs8Key != null) { test('export/import pkcs8 private key', () async { final keyData = await r._exportPrivatePkcs8Key(privateKey as PrivateKey); check(keyData.isNotEmpty, 'exported key is empty'); @@ -1432,7 +1452,7 @@ void _runTests( }); } - if (r._exportPrivateJsonWebKey != null && c.jwkImportKeyException == null) { + if (r._exportPrivateJsonWebKey != null) { test('export/import jwk private key', () async { final jwk = await r._exportPrivateJsonWebKey(privateKey as PrivateKey); check(jwk.isNotEmpty, 'exported key is empty'); @@ -1444,7 +1464,7 @@ void _runTests( //------------------------------ export/import public key - if (r._exportPublicRawKey != null && (c.pkcs8ImportKeyException == null || c.jwkImportKeyException == null)) { + if (r._exportPublicRawKey != null) { assert(!r._isSymmetric && r._importPublicRawKey != null); test('export/import raw public key', () async { @@ -1456,7 +1476,7 @@ void _runTests( }); } - if (r._exportPublicSpkiKey != null && c.pkcs8ImportKeyException == null) { + if (r._exportPublicSpkiKey != null) { assert(!r._isSymmetric && r._importPublicSpkiKey != null); test('export/import pkcs8 public key', () async { @@ -1468,7 +1488,7 @@ void _runTests( }); } - if (r._exportPublicJsonWebKey != null && c.jwkImportKeyException == null) { + if (r._exportPublicJsonWebKey != null) { assert(!r._isSymmetric && r._importPublicJsonWebKey != null); test('export/import jwk public key', () async { diff --git a/lib/src/testing/webcrypto/ecdh.dart b/lib/src/testing/webcrypto/ecdh.dart index 76d87197..bd4bd216 100644 --- a/lib/src/testing/webcrypto/ecdh.dart +++ b/lib/src/testing/webcrypto/ecdh.dart @@ -112,9 +112,18 @@ final _testData = [ "deriveParams": {} }, { - "name": "generated on boringssl/linux (import key exception) at 2020-01-22T23:24:34", + "name": "generated on boringssl/linux (pkcs8 import key exception) at 2020-01-22T23:24:34", "privatePkcs8KeyData": "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3aTiZ7odKAODYk4BpZlzulBCB/BptmxjtvrzyXI71UyhRANCAATl0GVa8O1sXXf2NV5qGJ/9/Vq8PVWCZuezADa1F0Vr2TaB8BseZIW+rhmEmLC2FfCdxj9NmLp00SilRTm40Hxm", + "publicRawKeyData": + "BHiIXxrwhM92v4ueDrj3x1JJY4uS+II/IJPjqMvaKj/QfoOllnEkrnaOW1owBYRBMnP0pPouPkqbVfPACMUsfKs=", + "publicSpkiKeyData": + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeIhfGvCEz3a/i54OuPfHUklji5L4gj8gk+Ooy9oqP9B+g6WWcSSudo5bWjAFhEEyc/Sk+i4+SptV88AIxSx8qw==", + "importKeyParams": {"curve": "p-256"}, + "importKeyException": "FormatException: incorrect elliptic curve" + }, + { + "name": "generated on boringssl/linux (jwk import key exception) at 2020-01-22T23:24:34", "privateJsonWebKeyData": { "kty": "EC", "crv": "P-256", @@ -132,14 +141,8 @@ final _testData = [ "x": "eIhfGvCEz3a_i54OuPfHUklji5L4gj8gk-Ooy9oqP9A", "y": "foOllnEkrnaOW1owBYRBMnP0pPouPkqbVfPACMUsfKs" }, - "derivedBits": "WA==", - "derivedLength": 7, "importKeyParams": {"curve": "p-256"}, - "importKeyException": { - "pkcs8Exception": "FormatException: incorrect elliptic curve", - "jwkException": "JWK property \"crv\" is not" - }, - "deriveParams": {} + "importKeyException": "JWK property \"crv\" is not" }, { "name": "generated on chrome/linux at 2020-01-22T23:24:39",