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.
109 lines
4.1 KiB
109 lines
4.1 KiB
package capsule_test
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"path/filepath"
|
|
"reflect"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
datekeys "g.activething.com/go/DateKeys"
|
|
"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.16 §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 != datekeys.SpecVersion || !strings.Contains(f.Description, "v0.16") || len(f.Cases) < 140 {
|
|
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, reason 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)
|
|
}
|
|
reason = string(d.SealReason)
|
|
}
|
|
if !reflect.DeepEqual(signers, c.Signers) || !reflect.DeepEqual(foreign, c.Foreign) || holder != c.SealHolder || when != c.SealTime || reason != c.SealReason {
|
|
t.Errorf("signers %+v foreign %+v seal %q %q %q; want %+v %+v %q %q %q", signers, foreign, holder, when, reason, c.Signers, c.Foreign, c.SealHolder, c.SealTime, c.SealReason)
|
|
}
|
|
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, SealReason: string(l.Reason)}
|
|
if !l.SealTime.IsZero() {
|
|
r.SealTime = l.SealTime.UTC().Format(time.RFC3339Nano)
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return out
|
|
}
|