You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dateKeys-dart/test/cms_support.dart

129 lines
4.1 KiB

// The differential of ECDSA and RSA against the Go reference: the cases
// of test/vectors/cms_ecdsa.json and cms_rsa.json, which
// tool/cms_go_vectors_test.go writes with the ECDSA and RSA of Go, run
// through ecdsa.dart, rsa.dart and nist_curves.dart, with the same results.
// It reads no file itself, so that the tests compiled to JavaScript run it
// too, on the part of the cases that cms_vectors.g.dart holds.
library;
import 'dart:typed_data';
import 'package:datekeys/src/bytes.dart';
import 'package:datekeys/src/ecdsa.dart';
import 'package:datekeys/src/nist_curves.dart';
import 'package:datekeys/src/rsa.dart';
import 'package:test/test.dart';
typedef Json = Map<String, Object?>;
/// The names of the vector files, cms_<name>.json.
const cmsFiles = [
'ecdsa',
'rsa',
'certs',
'signatures',
'algorithms',
'tokens',
'mutations',
'corpus',
];
/// The cases of [section] of [file].
List<Json> cases(Json file, String section) =>
(file[section]! as List).cast<Json>();
Uint8List hexOf(Object? v) => fromHex(v! as String);
/// A short name of the case [c], for the reasons of the expectations.
String caseName(Json c) =>
(c['name'] ??
(c['names'] as List?)?.first ??
c['fixture'] ??
'${c['base']} ${c['path']} ${c['op']} ${c['arg'] ?? ''}')
.toString();
// ---------------------------------------------------------------------------
// The tests of each file
final _curves = {'P-256': p256, 'P-384': p384, 'P-521': p521};
final _hashes = {
'SHA-256': Sha2.sha256,
'SHA-384': Sha2.sha384,
'SHA-512': Sha2.sha512,
};
/// The tests of cms_ecdsa.json.
void ecdsaTests(Json file) {
test('the curves are those of Go', () {
for (final c in cases(file, 'curves')) {
final curve = _curves[c['name']]!;
expect(curve.p, BigInt.parse(c['p']! as String, radix: 16));
expect(curve.n, BigInt.parse(c['n']! as String, radix: 16));
expect(curve.b, BigInt.parse(c['b']! as String, radix: 16));
expect(curve.gx, BigInt.parse(c['gx']! as String, radix: 16));
expect(curve.gy, BigInt.parse(c['gy']! as String, radix: 16));
expect(curve.p.bitLength, c['bits']);
expect(curve.byteLength, ((c['bits']! as int) + 7) ~/ 8);
}
});
test('a point reads as ecdsa.ParseUncompressedPublicKey reads it', () {
for (final c in cases(file, 'points')) {
final p = decodeUncompressed(_curves[c['curve']]!, hexOf(c['point']));
expect(p != null, c['ok'], reason: caseName(c));
}
});
test('a signature verifies as ecdsa.VerifyASN1 verifies it', () {
final keys = [
for (final k in cases(file, 'keys'))
decodeUncompressed(_curves[k['curve']]!, hexOf(k['point']))!,
];
for (final c in cases(file, 'verify')) {
expect(
verifyEcdsaAsn1(
keys[c['key']! as int],
hexOf(c['hash']),
hexOf(c['sig']),
),
c['valid'],
reason: caseName(c),
);
}
});
}
/// The tests of cms_rsa.json.
void rsaTests(Json file) {
test('the DigestInfo of each hash is that of Go', () {
final info = file['digest_info']! as Json;
for (final MapEntry(:key, :value) in _hashes.entries) {
expect(toHex(value.digestInfoPrefix), info[key], reason: key);
}
});
test(
'a signature verifies as rsa.VerifyPKCS1v15 and VerifyPSS verify it',
() {
final keys = [
for (final k in cases(file, 'keys'))
RsaPublicKey(
BigInt.parse(k['n']! as String, radix: 16),
k['e']! as int,
),
];
for (final (i, k) in cases(file, 'keys').indexed) {
expect(keys[i].n.bitLength, k['bits'], reason: caseName(k));
}
for (final c in [...cases(file, 'valid'), ...cases(file, 'verify')]) {
final key = keys[c['key']! as int];
final hash = _hashes[c['hash']]!;
final digest = hexOf(c['digest']);
final sig = hexOf(c['sig']);
final valid = c['scheme'] == 'pss'
? verifyPss(key, hash, digest, sig)
: verifyPkcs1v15(key, hash, digest, sig);
expect(valid, c['valid'], reason: caseName(c));
}
},
);
}

Powered by TurnKey Linux.