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.
197 lines
6.9 KiB
197 lines
6.9 KiB
// The verdicts of a signature of alg 2 and of a seal of seal_type 2 against
|
|
// Go, on the VM:
|
|
//
|
|
// - every case of testdata/vectors/security_cms.json, frozen by the Go
|
|
// reference at the draft v0.12, read in its context as TestCMSVectors of
|
|
// Go reads it, with its verdicts, the result of each signer, the authority
|
|
// and t of a valid seal, and its lines, byte for byte;
|
|
// - every case of test/vectors/securitycms_vectors.json, which
|
|
// tool/security_go_vectors.go makes and evaluates with package capsule of
|
|
// the reference: signers of every result, required and foreign, the
|
|
// validity of a certificate at the time of its seal, t plus the accuracy
|
|
// against the round time at the nanosecond, a seal of each kind beside a
|
|
// signature of each kind, and mutations;
|
|
// - and the part of both that securitycms_vectors.g.dart holds for the
|
|
// tests compiled to JavaScript, which must be that of the files.
|
|
@TestOn('vm')
|
|
library;
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:datekeys/datekeys.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import 'open_vectors_support.dart';
|
|
import 'security_support.dart';
|
|
import 'securitycms_support.dart';
|
|
import 'vectors/securitycms_vectors.g.dart';
|
|
|
|
Json readJson(String path) => jsonDecode(File(path).readAsStringSync()) as Json;
|
|
|
|
void main() {
|
|
group('security_cms.json', () {
|
|
final f = readJson('testdata/vectors/security_cms.json');
|
|
final cases = (f['cases']! as List).cast<Json>();
|
|
|
|
test('has the 135 cases of its README, which reach every verdict but X '
|
|
'and F3', () {
|
|
expect(f['spec'], specVersion);
|
|
expect(f['description'], contains('v0.12'));
|
|
expect(cases, hasLength(135));
|
|
expect({for (final c in cases) c['name']}, hasLength(135));
|
|
final reached = {
|
|
for (final c in cases) ...[c['signature'], c['seal']],
|
|
};
|
|
expect(reached, {
|
|
'F0', 'F1', 'F2', 'F4', 'F5', 'F6', //
|
|
'S0', 'S1', 'S2', 'S3', 'S4', 'S5',
|
|
});
|
|
// Every result of a signer, and a foreign one.
|
|
final results = {
|
|
for (final c in cases)
|
|
for (final s in (c['signers'] as List? ?? const []).cast<Json>())
|
|
s['result'],
|
|
};
|
|
expect(results, {for (final r in SignerResult.values) r.code});
|
|
expect(cases.where((c) => c['foreign_signers'] != null), isNotEmpty);
|
|
});
|
|
|
|
for (final c in cases) {
|
|
test(str(c, 'name'), () {
|
|
expect(cmsVectorDifferences(c), isEmpty);
|
|
});
|
|
}
|
|
});
|
|
|
|
group('securitycms_vectors.json', () {
|
|
final f = readJson('test/vectors/securitycms_vectors.json');
|
|
final cases = (f['cases']! as List).cast<Json>();
|
|
final chunks = chunksOf(f);
|
|
final bases = basesOf(f, chunks);
|
|
final contexts = contextsOf(f);
|
|
final texts = (f['texts']! as List).cast<String>();
|
|
|
|
test('is of this spec, from its generator, with every verdict and every '
|
|
'result of a signer, required and foreign', () {
|
|
expect(f['spec'], specVersion);
|
|
expect(f['generator'], 'tool/security_go_vectors.go');
|
|
expect(cases, hasLength(greaterThan(700)));
|
|
final verdicts = {
|
|
for (final c in cases) ...[c['signature'], c['seal']],
|
|
};
|
|
expect(verdicts, containsAll(<String>['F0', 'F1', 'F2', 'F4', 'F5']));
|
|
expect(verdicts, containsAll(<String>['F6', 'S0', 'S1', 'S2', 'S3']));
|
|
expect(verdicts, containsAll(<String>['S4', 'S5']));
|
|
Set<Object?> resultsOf(String list) => {
|
|
for (final c in cases)
|
|
if (c['detail'] case final Json d)
|
|
for (final s in (d[list]! as List).cast<Json>()) s['result'],
|
|
};
|
|
final all = {for (final r in SignerResult.values) r.code};
|
|
expect(resultsOf('signers'), all);
|
|
expect(resultsOf('foreign'), all.difference({'absent'}));
|
|
// A seal before the round time and one that is not, for a signer
|
|
// and for key 3, and Go's zero time, which gives no earliest seal.
|
|
final befores = {
|
|
for (final c in cases)
|
|
if (c['detail'] case final Json d)
|
|
for (final s in (d['signers']! as List).cast<Json>()) s['before'],
|
|
};
|
|
expect(befores, {true, false});
|
|
expect(
|
|
cases.where(
|
|
(c) =>
|
|
c['seal'] == 'S4' &&
|
|
c['sealed_at'] == null &&
|
|
c['detail'] != null,
|
|
),
|
|
isNotEmpty,
|
|
);
|
|
expect(contexts.where((c) => c.roundTime == null), isNotEmpty);
|
|
});
|
|
|
|
test('every case, with the verdicts, the lines, the detail and the '
|
|
'earliest seal of Go', () {
|
|
for (final c in cases) {
|
|
final area = cmsAreaOf(c, chunks, bases);
|
|
expect(
|
|
evaluateDifferences(c, area, contexts, texts),
|
|
isEmpty,
|
|
reason: c['name'] as String? ?? canonical(c),
|
|
);
|
|
}
|
|
});
|
|
|
|
test('securitycms_vectors.g.dart holds a part of it', () {
|
|
final part = jsonDecode(securityCmsVectorsJson) as Json;
|
|
for (final k in ['spec', 'generator', 'contexts', 'texts']) {
|
|
expect(canonical(part[k]), canonical(f[k]), reason: k);
|
|
}
|
|
expect(
|
|
[for (final b in basesOf(part, const [])) toHex(b)],
|
|
[for (final b in bases) toHex(b)],
|
|
);
|
|
// Each case of the part is one of the file, in the same order, with
|
|
// the same area.
|
|
String key(Json c) => canonical({
|
|
for (final e in c.entries)
|
|
if (e.key != 'pieces' && e.key != 'hex') e.key: e.value,
|
|
});
|
|
final some = (part['cases']! as List).cast<Json>();
|
|
expect(some, hasLength(greaterThan(40)));
|
|
var at = 0;
|
|
for (final c in some) {
|
|
while (at < cases.length && key(cases[at]) != key(c)) {
|
|
at++;
|
|
}
|
|
expect(at, lessThan(cases.length), reason: key(c));
|
|
expect(
|
|
cmsAreaOf(c, const [], bases),
|
|
cmsAreaOf(cases[at], chunks, bases),
|
|
reason: key(c),
|
|
);
|
|
}
|
|
});
|
|
});
|
|
|
|
test('the fixtures of securitycms_vectors.g.dart are those of testdata/, '
|
|
'with what their records say', () {
|
|
final fixtures =
|
|
((jsonDecode(securityCmsFixturesJson) as Json)['fixtures']! as List)
|
|
.cast<Json>();
|
|
expect(
|
|
[for (final x in fixtures) x['name']],
|
|
['format3_signed_cms', 'format3_sealed'],
|
|
);
|
|
for (final x in fixtures) {
|
|
final name = str(x, 'name');
|
|
final r = readJson('testdata/fixtures/$name.json');
|
|
expect(
|
|
x['dkc'],
|
|
toHex(File('testdata/fixtures/${r['file']}').readAsBytesSync()),
|
|
reason: name,
|
|
);
|
|
for (final k in ['release', 'unlock_at', 'verdicts']) {
|
|
expect(canonical(x[k]), canonical(r[k]), reason: '$name: $k');
|
|
}
|
|
final sig = r['signature'] as Json?;
|
|
expect(
|
|
canonical(x['signer_results']),
|
|
canonical(sig?['signer_results']),
|
|
reason: name,
|
|
);
|
|
final seal = r['seal'] as Json?;
|
|
expect(
|
|
canonical(x['seal']),
|
|
canonical(
|
|
seal == null
|
|
? null
|
|
: {'holder': seal['holder'], 'time': seal['time']},
|
|
),
|
|
reason: name,
|
|
);
|
|
}
|
|
});
|
|
}
|