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.
129 lines
4.1 KiB
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));
|
|
}
|
|
},
|
|
);
|
|
}
|