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/securitycms_vm_test.dart

197 lines
6.9 KiB

Stage 5c: the verdicts of alg 2 and seal_type 2, and the opening gives them securitycms.dart ports evaluateCMS, signerLine and evaluateSeal of signature2.go of Go at the draft v0.12, on the reader of CMS of stage 5a, with the same order of checks: SIGNERS with its profile and at most 16 entries, then the SignedData; each required signer in the order of SIGNERS and each foreign one in the order of the encoding, valid, invalid, absent, not verifiable, without seal, with an invalid seal or out of validity at the time of its seal; F2, F5 and F6 with their detail; and the seal over SEAL_SUBJECT, S1 to S5 with the authority and t. A round time at Go's zero time is no round time, as IsZero, and Verdicts.sealedAt skips a seal at that time, as SealedAt. cmsReader is the default CmsEvaluator of evaluateSecurity, and so of evaluateSecurityInput and the opening: nothing that Go evaluates is left not evaluated; a caller that passes cms: null still gets the parts without CMS alone. encodeSigners and maxSigners are exported, as EncodeSigners and MaxSigners of Go. The tests compare every part with Go: the 135 cases of security_cms.json with the result of each signer, the 24 of security.json, the 56 signatures of alg 2 and 105 seals of seal_type 2 of security_vectors.json, the 755 cases of securitycms_vectors.json with their detail and earliest seal, the fixtures format3_signed_cms and format3_sealed, and their openings in open_cases.json. On Node.js, a part of the vectors and the two fixtures opened in full. 1572 tests on the VM and 332 on Node.js. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
// 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,
);
}
});
}

Powered by TurnKey Linux.