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/note_test.go

117 lines
5.1 KiB

package capsule_test
import (
"bytes"
"context"
"errors"
"strings"
"testing"
datekeys "g.activething.com/go/DateKeys"
"g.activething.com/go/DateKeys/capsule"
"g.activething.com/go/DateKeys/extension"
"g.activething.com/go/DateKeys/internal/testkit"
)
// Spec v0.11 §24.1, §62.1 rule 23: the public note is in PUBLIC_HEADER, in
// clear, and header_binding ties it to the control: changing it makes step 15
// fail.
func TestPublicNote(t *testing.T) {
opts := files3(t)
opts.PublicNote = "Cartas del viaje a Lisboa"
var dkc bytes.Buffer
if _, err := capsule.EncryptFiles(&dkc, []capsule.Source{source("nota.txt", "Hola.\n")}, opts); err != nil {
t.Fatal(err)
}
in, err := capsule.Inspect(bytes.NewReader(dkc.Bytes()), capsule.InspectOptions{Registry: testkit.Registry()})
if err != nil {
t.Fatal(err)
}
if note, ok := in.Header.PublicNote(); !ok || note != "Cartas del viaje a Lisboa" {
t.Errorf("the note: %q %v", note, ok)
}
// The same bytes with another letter in the note: it still inspects, and
// Open fails at step 15 with ERR_HEADER_BINDING.
changed := bytes.Replace(dkc.Bytes(), []byte("Lisboa"), []byte("Lisbon"), 1)
if bytes.Equal(changed, dkc.Bytes()) {
t.Fatal("the note is not in clear in the capsule")
}
o := defaultOpen(1000)
o.Sink = &testkit.MemorySink{}
if _, err := capsule.Open(context.Background(), nil, bytes.NewReader(changed), o); !errors.Is(err, datekeys.ErrHeaderBinding) {
t.Errorf("a note changed: %v", err)
}
if _, err := capsule.Open(context.Background(), nil, bytes.NewReader(dkc.Bytes()), o); err != nil {
t.Errorf("the capsule with its note: %v", err)
}
}
func TestPublicNoteRules(t *testing.T) {
for name, text := range map[string]string{
"a tab": "a\tb",
"a line feed": "a\nb",
"a space at the end": "a ",
"a space at the start": " a",
"too long": strings.Repeat("a", extension.MaxNoteLen+1),
"not UTF-8": "\xff",
} {
if err := extension.CheckNote(text); err == nil {
t.Errorf("%s: accepted", name)
}
opts := files3(t)
opts.PublicNote = text
if _, err := capsule.EncryptFiles(&bytes.Buffer{}, []capsule.Source{source("a", "x")}, opts); err == nil {
t.Errorf("%s: written", name)
}
}
if err := extension.CheckNote(strings.Repeat("a", extension.MaxNoteLen)); err != nil {
t.Errorf("1024 bytes: %v", err)
}
// An unusable note shows nothing.
if _, ok := extension.Note([]extension.Extension{{ID: extension.NoteID, Version: 1, Data: []byte("a\nb")}}); ok {
t.Error("an unusable note was shown")
}
// The registry knows it only in PUBLIC_HEADER, noncritical.
var reg extension.Standard
if !extension.KnownIn(reg, extension.NoteID, 1, extension.PublicHeader, extension.Noncritical) ||
extension.KnownIn(reg, extension.NoteID, 1, extension.Control, extension.Noncritical) ||
extension.KnownIn(reg, extension.NoteID, 1, extension.PublicHeader, extension.Critical) ||
extension.KnownIn(reg, extension.NoteID, 2, extension.PublicHeader, extension.Noncritical) {
t.Error("registration of datekeys.note")
}
if us := extension.CheckNoncriticalIn(extension.PublicHeader, []extension.Extension{{ID: extension.NoteID, Version: 1, Data: []byte("a\tb")}}, reg); len(us) != 1 {
t.Errorf("the note with a tab is not unusable: %v", us)
}
}
// Review: spec §72 forbids an encoder to write a registered extension where
// it is not registered. A note given as an extension is checked like
// PublicNote, and no array of a capsule but the noncritical one of
// PUBLIC_HEADER takes it. In CONTROL_CBOR, critical, it would have inspected
// well and failed after the date at step 14. datekeys.capsule goes in none.
func TestRegisteredExtensionsWhereRegistered(t *testing.T) {
note := extension.Extension{ID: extension.NoteID, Version: 1, Data: []byte("Cartas")}
tab := extension.Extension{ID: extension.NoteID, Version: 1, Data: []byte("a\tb")}
capsuleExt := extension.Extension{ID: extension.CapsuleID, Version: 1, Data: []byte{0xa0}}
for name, set := range map[string]func(*capsule.EncryptOptions){
"a note with a tab": func(o *capsule.EncryptOptions) { o.Noncritical = []extension.Extension{tab} },
"a note in critical": func(o *capsule.EncryptOptions) { o.Critical = []extension.Extension{note} },
"a note in the control": func(o *capsule.EncryptOptions) { o.ControlNoncritical = []extension.Extension{note} },
"a note in the control, critical": func(o *capsule.EncryptOptions) { o.ControlCritical = []extension.Extension{note} },
"a note in the head": func(o *capsule.EncryptOptions) { o.HeadNoncritical = []extension.Extension{note} },
"datekeys.capsule": func(o *capsule.EncryptOptions) { o.Noncritical = []extension.Extension{capsuleExt} },
} {
opts := files3(t)
set(&opts)
if _, err := capsule.EncryptFiles(&bytes.Buffer{}, []capsule.Source{source("a", "x")}, opts); err == nil {
t.Errorf("%s: written", name)
}
}
opts := files3(t)
opts.Noncritical = []extension.Extension{note}
var dkc bytes.Buffer
if _, err := capsule.EncryptFiles(&dkc, []capsule.Source{source("a", "x")}, opts); err != nil {
t.Fatalf("a valid note as an extension: %v", err)
}
}

Powered by TurnKey Linux.