Stage 5b: the commitments, SECURITY_CBOR and the verdicts of alg 1
author.dart ports what an author signs and a seal seals from
signature.go of datekeys-go: payload_commit, control_commit over
CONTROL_SIG in each format, head_digest, signers_digest, AUTHOR_MESSAGE
with its prefix and its 99 bytes, its code taken byte by byte as Go
takes it, SIG_PART and SEAL_SUBJECT.
security.dart ports SECURITY_CBOR and EvaluateSecurityIn: the outer
map, author-signature and seal with the schema and the limits of Go,
their encoders, and an evaluation that never throws. X for an outer map
that fails its layer 2 or 3, version 2 among them; F0 to F4 for the
signature, with verifyStrict for alg 1 and the key matched against the
saved ones by its dkauthor1 string; S0 to S2 for the seal; and a failure
inside one part fails that part only, as Go recovers a panic. Without a
context it reads as a reader of v0.10. securityContext is
newSecurityContext with the head digest, control_commit at zero when
CONTROL_SIG cannot be encoded, and holderText the rule of a name of a
certificate.
The signature of alg 2 and the seal of seal_type 2 belong to the reader
of CMS of stage 5c, behind the interface CmsEvaluator: without one their
verdict is null, not evaluated, never guessed.
verdicts.dart gains the texts of Go at the draft v0.12, Verdicts.lines
and sealedAt, Detail, SignerLine and SignerResult, and verdicts that may
be evaluated in part.
The tests check every case of security_vectors.json, security.json in its
context, the commitments, the signature and the seal of each fixture of
format 3, and the boundary with a reader of CMS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
// The security area on the VM and compiled to JavaScript: the part of the
|
|
|
|
|
// vectors of Go that test/vectors/security_vectors.g.dart holds, which
|
|
|
|
|
// tool/security_go_vectors.go writes with package capsule of the reference,
|
|
|
|
|
// and what the API does: the boundary with the reader of CMS of alg 2 and
|
|
|
|
|
// seal_type 2, an evaluation that never throws, and the context that the
|
|
|
|
|
// opening builds.
|
|
|
|
|
library;
|
|
|
|
|
|
|
|
|
|
import 'dart:convert';
|
|
|
|
|
import 'dart:math';
|
|
|
|
|
import 'dart:typed_data';
|
|
|
|
|
|
|
|
|
|
import 'package:datekeys/datekeys.dart';
|
|
|
|
|
import 'package:test/test.dart';
|
|
|
|
|
|
|
|
|
|
import 'open_vectors_support.dart';
|
|
|
|
|
import 'security_support.dart';
|
|
|
|
|
import 'vectors/security_vectors.g.dart';
|
|
|
|
|
|
|
|
|
|
final Json _vectors = jsonDecode(securityVectorsJson) as Json;
|
|
|
|
|
|
|
|
|
|
List<Json> _section(String name) => (_vectors[name]! as List).cast<Json>();
|
|
|
|
|
|
|
|
|
|
/// A reader of CMS that answers what it is given, and records its calls.
|
|
|
|
|
final class FakeCms implements CmsEvaluator {
|
|
|
|
|
FakeCms({this.signature, this.seal, this.throws = false});
|
|
|
|
|
|
|
|
|
|
final CmsSignatureVerdict? Function()? signature;
|
|
|
|
|
final CmsSealVerdict Function()? seal;
|
|
|
|
|
final bool throws;
|
|
|
|
|
final calls = <String>[];
|
|
|
|
|
Uint8List? signedWith;
|
|
|
|
|
bool? hasSeal;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
CmsSignatureVerdict? evaluateSignature(
|
|
|
|
|
Uint8List signers,
|
|
|
|
|
Uint8List value,
|
|
|
|
|
bool hasSeal,
|
|
|
|
|
SecurityContext context,
|
|
|
|
|
) {
|
|
|
|
|
calls.add('signature');
|
|
|
|
|
this.hasSeal = hasSeal;
|
|
|
|
|
if (throws) throw StateError('broken');
|
|
|
|
|
return signature!();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
CmsSealVerdict evaluateSeal(
|
|
|
|
|
Uint8List token,
|
|
|
|
|
Uint8List? signature,
|
|
|
|
|
SecurityContext context,
|
|
|
|
|
) {
|
|
|
|
|
calls.add('seal');
|
|
|
|
|
signedWith = signature;
|
|
|
|
|
if (throws) throw StateError('broken');
|
|
|
|
|
return seal!();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
test('the part of the vectors is of this spec, from its generator', () {
|
|
|
|
|
expect(_vectors['spec'], specVersion);
|
|
|
|
|
expect(_vectors['generator'], 'tool/security_go_vectors.go');
|
|
|
|
|
expect(_section('evaluate'), hasLength(greaterThan(150)));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('the commitments, as Go builds them', () {
|
|
|
|
|
expect(commitmentDifferences(_vectors['commitments']! as Json), isEmpty);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('the encoders, as Go writes them', () {
|
|
|
|
|
expect(encodeDifferences(_section('encode')), isEmpty);
|
|
|
|
|
expect(encodeSecurity(), hasLength(22));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('every eighth evaluation, with the verdicts and lines of Go', () {
|
|
|
|
|
final contexts = contextsOf(_vectors);
|
|
|
|
|
final texts = (_vectors['texts']! as List).cast<String>();
|
|
|
|
|
final bases = [
|
|
|
|
|
for (final b in (_vectors['bases']! as List).cast<String>()) fromHex(b),
|
|
|
|
|
];
|
|
|
|
|
for (final c in _section('evaluate')) {
|
|
|
|
|
final security = securityOf(c, bases);
|
|
|
|
|
expect(
|
|
|
|
|
evaluateDifferences(c, security, contexts, texts),
|
|
|
|
|
isEmpty,
|
|
|
|
|
reason: canonical(c),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('the lines and the earliest seal of every verdict and detail', () {
|
|
|
|
|
for (final c in _section('lines')) {
|
|
|
|
|
expect(lineDifferences(c), isEmpty, reason: str(c, 'name'));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('the name of a certificate, as holderText of Go', () {
|
|
|
|
|
final cases = _section('holder');
|
|
|
|
|
expect(cases, hasLength(greaterThan(200)));
|
|
|
|
|
for (final c in cases) {
|
|
|
|
|
expect(
|
|
|
|
|
holderText(nameOf(c), fromHex(str(c, 'hash'))),
|
|
|
|
|
c['result'],
|
|
|
|
|
reason: canonical(c),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
// A hash that is not a SHA-256 is an error of the caller.
|
|
|
|
|
expect(() => holderText('Ana', Uint8List(31)), throwsArgumentError);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
group('the reader of CMS', () {
|
|
|
|
|
final context = SecurityContext(
|
|
|
|
|
controlCommit: Uint8List(32)..[0] = 1,
|
|
|
|
|
headDigest: Uint8List(32)..[0] = 2,
|
|
|
|
|
roundTime: parseRfc3339('2030-01-01T00:00:00Z'),
|
|
|
|
|
);
|
|
|
|
|
final alg2 = encodeAuthorSignature(algCms, [0x80], [1, 2, 3]);
|
|
|
|
|
final seal2 = encodeSeal(sealTypeRfc3161, [4, 5, 6]);
|
|
|
|
|
final ana = SignerLine(
|
|
|
|
|
holder: 'Ana',
|
|
|
|
|
issuer: 'CA',
|
|
|
|
|
result: SignerResult.valid,
|
|
|
|
|
sealHolder: 'TSA',
|
|
|
|
|
sealTime: parseRfc3339('2026-09-30T12:00:00.5Z'),
|
|
|
|
|
before: true,
|
|
|
|
|
);
|
|
|
|
|
final tsaTime = parseRfc3339('2026-09-29T10:00:00Z');
|
|
|
|
|
|
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
|
|
|
test('is cmsReader by default, and the opening evaluates with it', () {
|
|
|
|
|
// SIGNERS empty is F1, and a token that is not DER, S2.
|
|
|
|
|
final v = evaluateSecurity(
|
|
|
|
|
encodeSecurityWith(signature: alg2, seal: seal2),
|
|
|
|
|
context: context,
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[v.signature, v.seal, v.evaluated],
|
|
|
|
|
[Verdict.signatureUnchecked, Verdict.sealUnreadable, true],
|
|
|
|
|
);
|
|
|
|
|
expect(v.lines, [
|
|
|
|
|
Verdict.signatureUnchecked.text,
|
|
|
|
|
Verdict.sealUnreadable.text,
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
Stage 5b: the commitments, SECURITY_CBOR and the verdicts of alg 1
author.dart ports what an author signs and a seal seals from
signature.go of datekeys-go: payload_commit, control_commit over
CONTROL_SIG in each format, head_digest, signers_digest, AUTHOR_MESSAGE
with its prefix and its 99 bytes, its code taken byte by byte as Go
takes it, SIG_PART and SEAL_SUBJECT.
security.dart ports SECURITY_CBOR and EvaluateSecurityIn: the outer
map, author-signature and seal with the schema and the limits of Go,
their encoders, and an evaluation that never throws. X for an outer map
that fails its layer 2 or 3, version 2 among them; F0 to F4 for the
signature, with verifyStrict for alg 1 and the key matched against the
saved ones by its dkauthor1 string; S0 to S2 for the seal; and a failure
inside one part fails that part only, as Go recovers a panic. Without a
context it reads as a reader of v0.10. securityContext is
newSecurityContext with the head digest, control_commit at zero when
CONTROL_SIG cannot be encoded, and holderText the rule of a name of a
certificate.
The signature of alg 2 and the seal of seal_type 2 belong to the reader
of CMS of stage 5c, behind the interface CmsEvaluator: without one their
verdict is null, not evaluated, never guessed.
verdicts.dart gains the texts of Go at the draft v0.12, Verdicts.lines
and sealedAt, Detail, SignerLine and SignerResult, and verdicts that may
be evaluated in part.
The tests check every case of security_vectors.json, security.json in its
context, the commitments, the signature and the seal of each fixture of
format 3, and the boundary with a reader of CMS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
test('without one, alg 2 and seal_type 2 are not evaluated', () {
|
|
|
|
|
final v = evaluateSecurity(
|
|
|
|
|
encodeSecurityWith(signature: alg2, seal: seal2),
|
|
|
|
|
context: context,
|
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
|
|
|
cms: null,
|
Stage 5b: the commitments, SECURITY_CBOR and the verdicts of alg 1
author.dart ports what an author signs and a seal seals from
signature.go of datekeys-go: payload_commit, control_commit over
CONTROL_SIG in each format, head_digest, signers_digest, AUTHOR_MESSAGE
with its prefix and its 99 bytes, its code taken byte by byte as Go
takes it, SIG_PART and SEAL_SUBJECT.
security.dart ports SECURITY_CBOR and EvaluateSecurityIn: the outer
map, author-signature and seal with the schema and the limits of Go,
their encoders, and an evaluation that never throws. X for an outer map
that fails its layer 2 or 3, version 2 among them; F0 to F4 for the
signature, with verifyStrict for alg 1 and the key matched against the
saved ones by its dkauthor1 string; S0 to S2 for the seal; and a failure
inside one part fails that part only, as Go recovers a panic. Without a
context it reads as a reader of v0.10. securityContext is
newSecurityContext with the head digest, control_commit at zero when
CONTROL_SIG cannot be encoded, and holderText the rule of a name of a
certificate.
The signature of alg 2 and the seal of seal_type 2 belong to the reader
of CMS of stage 5c, behind the interface CmsEvaluator: without one their
verdict is null, not evaluated, never guessed.
verdicts.dart gains the texts of Go at the draft v0.12, Verdicts.lines
and sealedAt, Detail, SignerLine and SignerResult, and verdicts that may
be evaluated in part.
The tests check every case of security_vectors.json, security.json in its
context, the commitments, the signature and the seal of each fixture of
format 3, and the boundary with a reader of CMS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[v.signature, v.seal, v.evaluated, v.lines],
|
|
|
|
|
[null, null, false, isEmpty],
|
|
|
|
|
);
|
|
|
|
|
final s = evaluateSecurity(
|
|
|
|
|
encodeSecurityWith(signature: alg2, seal: encodeSeal(1, [1])),
|
|
|
|
|
context: context,
|
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
|
|
|
cms: null,
|
Stage 5b: the commitments, SECURITY_CBOR and the verdicts of alg 1
author.dart ports what an author signs and a seal seals from
signature.go of datekeys-go: payload_commit, control_commit over
CONTROL_SIG in each format, head_digest, signers_digest, AUTHOR_MESSAGE
with its prefix and its 99 bytes, its code taken byte by byte as Go
takes it, SIG_PART and SEAL_SUBJECT.
security.dart ports SECURITY_CBOR and EvaluateSecurityIn: the outer
map, author-signature and seal with the schema and the limits of Go,
their encoders, and an evaluation that never throws. X for an outer map
that fails its layer 2 or 3, version 2 among them; F0 to F4 for the
signature, with verifyStrict for alg 1 and the key matched against the
saved ones by its dkauthor1 string; S0 to S2 for the seal; and a failure
inside one part fails that part only, as Go recovers a panic. Without a
context it reads as a reader of v0.10. securityContext is
newSecurityContext with the head digest, control_commit at zero when
CONTROL_SIG cannot be encoded, and holderText the rule of a name of a
certificate.
The signature of alg 2 and the seal of seal_type 2 belong to the reader
of CMS of stage 5c, behind the interface CmsEvaluator: without one their
verdict is null, not evaluated, never guessed.
verdicts.dart gains the texts of Go at the draft v0.12, Verdicts.lines
and sealedAt, Detail, SignerLine and SignerResult, and verdicts that may
be evaluated in part.
The tests check every case of security_vectors.json, security.json in its
context, the commitments, the signature and the seal of each fixture of
format 3, and the boundary with a reader of CMS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[s.signature, s.seal, s.lines],
|
|
|
|
|
[
|
|
|
|
|
null,
|
|
|
|
|
Verdict.sealUnsupported,
|
|
|
|
|
[Verdict.sealUnsupported.text],
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
final f = evaluateSecurity(
|
|
|
|
|
encodeSecurityWith(
|
|
|
|
|
signature: encodeAuthorSignature(9, [], []),
|
|
|
|
|
seal: seal2,
|
|
|
|
|
),
|
|
|
|
|
context: context,
|
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
|
|
|
cms: null,
|
Stage 5b: the commitments, SECURITY_CBOR and the verdicts of alg 1
author.dart ports what an author signs and a seal seals from
signature.go of datekeys-go: payload_commit, control_commit over
CONTROL_SIG in each format, head_digest, signers_digest, AUTHOR_MESSAGE
with its prefix and its 99 bytes, its code taken byte by byte as Go
takes it, SIG_PART and SEAL_SUBJECT.
security.dart ports SECURITY_CBOR and EvaluateSecurityIn: the outer
map, author-signature and seal with the schema and the limits of Go,
their encoders, and an evaluation that never throws. X for an outer map
that fails its layer 2 or 3, version 2 among them; F0 to F4 for the
signature, with verifyStrict for alg 1 and the key matched against the
saved ones by its dkauthor1 string; S0 to S2 for the seal; and a failure
inside one part fails that part only, as Go recovers a panic. Without a
context it reads as a reader of v0.10. securityContext is
newSecurityContext with the head digest, control_commit at zero when
CONTROL_SIG cannot be encoded, and holderText the rule of a name of a
certificate.
The signature of alg 2 and the seal of seal_type 2 belong to the reader
of CMS of stage 5c, behind the interface CmsEvaluator: without one their
verdict is null, not evaluated, never guessed.
verdicts.dart gains the texts of Go at the draft v0.12, Verdicts.lines
and sealedAt, Detail, SignerLine and SignerResult, and verdicts that may
be evaluated in part.
The tests check every case of security_vectors.json, security.json in its
context, the commitments, the signature and the seal of each fixture of
format 3, and the boundary with a reader of CMS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[f.signature, f.seal, f.lines],
|
|
|
|
|
[
|
|
|
|
|
Verdict.signatureUnchecked,
|
|
|
|
|
null,
|
|
|
|
|
[Verdict.signatureUnchecked.text],
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
expect('$f', 'Verdicts(F1, not evaluated)');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('without a context it is never asked, as a reader of v0.10', () {
|
|
|
|
|
final cms = FakeCms();
|
|
|
|
|
final v = evaluateSecurity(
|
|
|
|
|
encodeSecurityWith(signature: alg2, seal: seal2),
|
|
|
|
|
cms: cms,
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[v.signature, v.seal],
|
|
|
|
|
[Verdict.signatureUnchecked, Verdict.sealUnsupported],
|
|
|
|
|
);
|
|
|
|
|
expect(cms.calls, isEmpty);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('gives F2, F5 or F6 with the signers, and the seal with its '
|
|
|
|
|
'authority, in one detail', () {
|
|
|
|
|
final cms = FakeCms(
|
|
|
|
|
signature: () =>
|
|
|
|
|
CmsSignatureVerdict(Verdict.signedComplete, Detail(signers: [ana])),
|
|
|
|
|
seal: () =>
|
|
|
|
|
CmsSealVerdict(Verdict.sealed, holder: 'TSA 2', time: tsaTime),
|
|
|
|
|
);
|
|
|
|
|
final security = encodeSecurityWith(signature: alg2, seal: seal2);
|
|
|
|
|
final v = evaluateSecurity(security, context: context, cms: cms);
|
|
|
|
|
expect([v.signature, v.seal], [Verdict.signedComplete, Verdict.sealed]);
|
|
|
|
|
expect(cms.calls, ['signature', 'seal']);
|
|
|
|
|
expect([cms.hasSeal, cms.signedWith], [true, alg2]);
|
|
|
|
|
expect(v.detail!.signers, [ana]);
|
|
|
|
|
expect([v.detail!.sealHolder, v.detail!.sealTime], ['TSA 2', tsaTime]);
|
|
|
|
|
// The lines are those of these verdicts, which the vectors of Go
|
|
|
|
|
// check: those of F6 with its signer, and S4 with its authority.
|
|
|
|
|
final merged = Verdicts(
|
|
|
|
|
signature: Verdict.signedComplete,
|
|
|
|
|
seal: Verdict.sealed,
|
|
|
|
|
detail: Detail(signers: [ana], sealHolder: 'TSA 2', sealTime: tsaTime),
|
|
|
|
|
);
|
|
|
|
|
expect(v.lines, merged.lines);
|
|
|
|
|
expect(v.lines, hasLength(4));
|
|
|
|
|
expect(v.sealedAt, tsaTime);
|
|
|
|
|
// A seal without a signature seals SIG_PART 0x00.
|
|
|
|
|
final alone = evaluateSecurity(
|
|
|
|
|
encodeSecurityWith(seal: seal2),
|
|
|
|
|
context: context,
|
|
|
|
|
cms: cms,
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[alone.signature, alone.seal, cms.signedWith],
|
|
|
|
|
[Verdict.noSignature, Verdict.sealed, null],
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('null is F1, and S1 to S3 name no authority', () {
|
|
|
|
|
final cms = FakeCms(
|
|
|
|
|
signature: () => null,
|
|
|
|
|
seal: () =>
|
|
|
|
|
CmsSealVerdict(Verdict.sealInvalid, holder: 'x', time: tsaTime),
|
|
|
|
|
);
|
|
|
|
|
final v = evaluateSecurity(
|
|
|
|
|
encodeSecurityWith(signature: alg2, seal: seal2),
|
|
|
|
|
context: context,
|
|
|
|
|
cms: cms,
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[v.signature, v.seal, v.detail],
|
|
|
|
|
[Verdict.signatureUnchecked, Verdict.sealInvalid, null],
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('what it throws, or a verdict out of its range, fails its own part '
|
|
|
|
|
'only, as a panic in Go', () {
|
|
|
|
|
final security = encodeSecurityWith(signature: alg2, seal: seal2);
|
|
|
|
|
final broken = evaluateSecurity(
|
|
|
|
|
security,
|
|
|
|
|
context: context,
|
|
|
|
|
cms: FakeCms(throws: true),
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[broken.signature, broken.seal, broken.detail],
|
|
|
|
|
[Verdict.signatureUnchecked, Verdict.sealUnreadable, null],
|
|
|
|
|
);
|
|
|
|
|
for (final (sig, seal) in [
|
|
|
|
|
(
|
|
|
|
|
() => CmsSignatureVerdict(Verdict.signedSaved, Detail()),
|
|
|
|
|
() => const CmsSealVerdict(Verdict.noSeal),
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
() => CmsSignatureVerdict(Verdict.unreadable, Detail()),
|
|
|
|
|
() => const CmsSealVerdict(Verdict.sealed, holder: 'no time'),
|
|
|
|
|
),
|
|
|
|
|
]) {
|
|
|
|
|
final v = evaluateSecurity(
|
|
|
|
|
security,
|
|
|
|
|
context: context,
|
|
|
|
|
cms: FakeCms(signature: sig, seal: seal),
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[v.signature, v.seal, v.detail],
|
|
|
|
|
[Verdict.signatureUnchecked, Verdict.sealUnreadable, null],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
// The seal fails, and the signers of the signature stay.
|
|
|
|
|
final half = evaluateSecurity(
|
|
|
|
|
security,
|
|
|
|
|
context: context,
|
|
|
|
|
cms: FakeCms(
|
|
|
|
|
signature: () => CmsSignatureVerdict(
|
|
|
|
|
Verdict.signedIncomplete,
|
|
|
|
|
Detail(signers: [ana]),
|
|
|
|
|
),
|
|
|
|
|
seal: () => throw StateError('broken'),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[half.signature, half.seal],
|
|
|
|
|
[Verdict.signedIncomplete, Verdict.sealUnreadable],
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
[half.detail!.signers, half.detail!.sealTime],
|
|
|
|
|
[
|
|
|
|
|
[ana],
|
|
|
|
|
null,
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('never throws, whatever the area holds', () {
|
|
|
|
|
final r = Random(20261005);
|
|
|
|
|
final valid = encodeSecurityWith(
|
|
|
|
|
signature: encodeAuthorSignature(1, Uint8List(32), Uint8List(64)),
|
|
|
|
|
seal: encodeSeal(1, [1]),
|
|
|
|
|
);
|
|
|
|
|
final context = SecurityContext(
|
|
|
|
|
controlCommit: Uint8List(32),
|
|
|
|
|
headDigest: Uint8List(32),
|
|
|
|
|
);
|
|
|
|
|
for (var i = 0; i < 300; i++) {
|
|
|
|
|
final b = Uint8List.fromList(valid);
|
|
|
|
|
for (var j = 0; j < 1 + r.nextInt(3); j++) {
|
|
|
|
|
b[r.nextInt(b.length)] = r.nextInt(256);
|
|
|
|
|
}
|
|
|
|
|
final cut = Uint8List.sublistView(b, 0, r.nextInt(b.length + 1));
|
|
|
|
|
for (final area in [
|
|
|
|
|
b,
|
|
|
|
|
cut,
|
|
|
|
|
Uint8List.fromList(List.generate(r.nextInt(40), (_) => r.nextInt(256))),
|
|
|
|
|
]) {
|
|
|
|
|
for (final ctx in [null, context]) {
|
|
|
|
|
final v = evaluateSecurity(area, context: ctx);
|
|
|
|
|
expect(v.evaluated, isTrue);
|
|
|
|
|
expect(v.lines, isNotEmpty);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('the context of the opening: control_commit, head_digest, the round '
|
|
|
|
|
'time and the keys', () {
|
|
|
|
|
final built =
|
|
|
|
|
((_vectors['commitments']! as Json)['control_commit']! as List)
|
|
|
|
|
.cast<Json>()
|
|
|
|
|
.firstWhere((c) => c['decode_format'] == 3 && c['format'] == 3);
|
|
|
|
|
final control = decodeControl(
|
|
|
|
|
fromHex(str(built, 'control')),
|
|
|
|
|
CapsuleFormat.format3,
|
|
|
|
|
);
|
|
|
|
|
final head = Uint8List.fromList(utf8.encode('a head'));
|
|
|
|
|
final keys = {'dkauthor1x': 'Ana'};
|
|
|
|
|
final input = SecurityInput(
|
|
|
|
|
security: encodeSecurity(),
|
|
|
|
|
head: head,
|
|
|
|
|
control: control,
|
|
|
|
|
format: CapsuleFormat.format3,
|
|
|
|
|
roundTime: parseRfc3339('2030-01-01T00:00:00Z'),
|
|
|
|
|
authorKeys: keys,
|
|
|
|
|
);
|
|
|
|
|
final c = securityContext(input);
|
|
|
|
|
expect(toHex(c.controlCommit), built['commit']);
|
|
|
|
|
expect(c.headDigest, headDigest(head));
|
|
|
|
|
expect([c.roundTime, c.authorKeys], [input.roundTime, keys]);
|
|
|
|
|
expect(
|
|
|
|
|
[
|
|
|
|
|
evaluateSecurityInput(input).signature,
|
|
|
|
|
evaluateSecurityInput(input).seal,
|
|
|
|
|
],
|
|
|
|
|
[Verdict.noSignature, Verdict.noSeal],
|
|
|
|
|
);
|
|
|
|
|
// A control that CONTROL_SIG cannot hold leaves control_commit at zero,
|
|
|
|
|
// as in Go.
|
|
|
|
|
final odd = securityContext(
|
|
|
|
|
SecurityInput(
|
|
|
|
|
security: input.security,
|
|
|
|
|
head: head,
|
|
|
|
|
control: control,
|
|
|
|
|
format: CapsuleFormat.format1,
|
|
|
|
|
roundTime: input.roundTime,
|
|
|
|
|
authorKeys: const {},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
expect(odd.controlCommit, Uint8List(32));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('the texts of the verdicts and of the results', () {
|
|
|
|
|
// S0 shows nothing, and the verdicts that name a key, a holder or a
|
|
|
|
|
// time have their text in the lines.
|
|
|
|
|
for (final v in Verdict.values) {
|
|
|
|
|
expect(v.text.isEmpty, {'S0', 'F3', 'F4', 'F6', 'S4'}.contains(v.code));
|
|
|
|
|
}
|
|
|
|
|
for (final r in SignerResult.values) {
|
|
|
|
|
expect(SignerResult.fromCode(r.code), r);
|
|
|
|
|
}
|
|
|
|
|
expect(SignerResult.fromCode('valida'), isNull);
|
|
|
|
|
expect(Verdicts.notEvaluated.lines, isEmpty);
|
|
|
|
|
expect(Verdicts.failed(StateError('x')).lines, isEmpty);
|
|
|
|
|
});
|
|
|
|
|
}
|