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/capsule/cmsvectors_test.go

107 lines
3.9 KiB

package capsule_test
import (
"encoding/hex"
"path/filepath"
"reflect"
"slices"
"strings"
"testing"
"time"
"g.activething.com/go/DateKeys/capsule"
"g.activething.com/go/DateKeys/internal/testkit"
)
// testdata/vectors/security_cms.json is frozen: each case is evaluated again,
// with its context, and must give its verdicts, the result of each signer,
// the authority and the time of a valid seal, and its lines, byte for byte
// (spec v0.12 §29.7, §29.10, §29.11).
func TestCMSVectors(t *testing.T) {
var f testkit.CMSVectorFile
if err := testkit.ReadJSON(filepath.Join("..", "testdata", "vectors", "security_cms.json"), &f); err != nil {
t.Fatal(err)
}
if f.Spec != "0.12" || !strings.Contains(f.Description, "v0.12") || len(f.Cases) < 100 {
t.Fatalf("spec %q, %d cases: %s", f.Spec, len(f.Cases), f.Description)
}
seen := map[string]bool{}
verdicts := map[string]bool{}
for _, c := range f.Cases {
if seen[c.Name] {
t.Errorf("two cases named %q", c.Name)
}
seen[c.Name] = true
verdicts[c.Signature] = true
verdicts[c.Seal] = true
t.Run(c.Name, func(t *testing.T) {
area, err := hex.DecodeString(c.SecurityCBOR)
if err != nil {
t.Fatal(err)
}
var sc capsule.SecurityContext
cc, err1 := hex.DecodeString(c.Context.ControlCommit)
hd, err2 := hex.DecodeString(c.Context.HeadDigest)
if err1 != nil || err2 != nil || len(cc) != 32 || len(hd) != 32 {
t.Fatalf("the context: %+v", c.Context)
}
copy(sc.ControlCommit[:], cc)
copy(sc.HeadDigest[:], hd)
if sc.RoundTime, err = time.Parse(time.RFC3339, c.Context.RoundTime); err != nil {
t.Fatal(err)
}
v := capsule.EvaluateSecurityIn(area, &sc)
if string(v.Signature) != c.Signature || string(v.Seal) != c.Seal {
t.Fatalf("verdicts %s and %s, want %s and %s", v.Signature, v.Seal, c.Signature, c.Seal)
}
var signers, foreign []testkit.FixtureSignerResult
var holder, when string
if d := v.Detail; d != nil {
signers, foreign = vectorSignerResults(d.Signers), vectorSignerResults(d.Foreign)
if !d.SealTime.IsZero() {
holder, when = d.SealHolder, d.SealTime.UTC().Format(time.RFC3339Nano)
}
}
if !reflect.DeepEqual(signers, c.Signers) || !reflect.DeepEqual(foreign, c.Foreign) || holder != c.SealHolder || when != c.SealTime {
t.Errorf("signers %+v foreign %+v seal %q %q; want %+v %+v %q %q", signers, foreign, holder, when, c.Signers, c.Foreign, c.SealHolder, c.SealTime)
}
if lines := v.Lines(); !slices.Equal(lines, c.Lines) {
t.Errorf("lines %q, want %q", lines, c.Lines)
}
// No line of the verdicts carries a control or a bidi character,
// whatever the certificates say (spec §29.7).
for _, line := range c.Lines {
for _, r := range line {
if r < 0x20 || r >= 0x7f && r <= 0x9f || r >= 0x202a && r <= 0x202e || r >= 0x2066 && r <= 0x2069 || r == 0xfeff {
t.Errorf("a line with %U: %q", r, line)
}
}
}
})
}
// Every verdict of alg 2 and of seal_type 2 has a case.
for _, want := range []capsule.Verdict{
capsule.VerdictNoSignature, capsule.VerdictSignatureUnchecked, capsule.VerdictSignatureInvalid, capsule.VerdictSignedOther,
capsule.VerdictSignedIncomplete, capsule.VerdictSignedComplete, capsule.VerdictNoSeal, capsule.VerdictSealUnsupported,
capsule.VerdictSealUnreadable, capsule.VerdictSealInvalid, capsule.VerdictSealed, capsule.VerdictSealedLate,
} {
if !verdicts[string(want)] {
t.Errorf("no case gives %s", want)
}
}
}
// vectorSignerResults are the results of the signers as security_cms.json
// writes them: t with the fraction of its token when it has one.
func vectorSignerResults(lines []capsule.SignerLine) []testkit.FixtureSignerResult {
var out []testkit.FixtureSignerResult
for _, l := range lines {
r := testkit.FixtureSignerResult{Holder: l.Holder, Issuer: l.Issuer, Result: l.Result, Before: l.Before}
if !l.SealTime.IsZero() {
r.SealTime = l.SealTime.UTC().Format(time.RFC3339Nano)
}
out = append(out, r)
}
return out
}

Powered by TurnKey Linux.