Test data: security.json in the context of a capsule, with v0.12 verdicts

The review found that security.json said spec 0.11 and still gave the
verdicts of a reader of v0.10, evaluated without context, contrary to what
section 76 announced (D1).

- security.json carries the context of a capsule, its commitments and the
  time of its round, and each case its verdicts and the lines of the
  official SDK in it: a signature of alg 1 that does not verify is F2, a
  token of seal_type 2 that is not DER is S2, and new cases give a valid
  signature of alg 1 (F4) and alg and seal_type 4294967295 (F1, S1).
- mutations.json: the signature of alg 1 that does not verify (F2) is a
  case of 64, and the seal that opens with S1 uses seal_type 4294967295,
  not seal_type 1, which a later version may define.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.12
dev 6 days ago
parent 0f51af780a
commit aaf0f41156

@ -1,13 +1,16 @@
package testkit
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"strings"
"time"
datekeys "g.activething.com/go/DateKeys"
"g.activething.com/go/DateKeys/authorkey"
"g.activething.com/go/DateKeys/capsule"
"g.activething.com/go/DateKeys/internal/cbortest"
"g.activething.com/go/DateKeys/internal/pathrule"
@ -87,22 +90,56 @@ type HeadVector struct {
}
// SecurityVectorFile is testdata/vectors/security.json: SECURITY_CBOR and
// its verdicts (spec §29.3, §29.7).
// its verdicts (spec §29.3, §29.7), all in one context, the commitments of a
// capsule and the time of its round, as a reader of this version reads them.
type SecurityVectorFile struct {
Spec string `json:"spec"`
Description string `json:"description"`
Context CMSVectorContext `json:"context"`
Vectors []SecurityVector `json:"vectors"`
}
// SecurityVector is SECURITY_CBOR, exactly its SECURITY_LEN bytes, and the
// verdicts of the signature and of the seal.
// SecurityVector is SECURITY_CBOR, exactly its SECURITY_LEN bytes, the
// verdicts of the signature and of the seal in the context of the file, and
// the lines that the official SDK shows.
type SecurityVector struct {
Name string `json:"name"`
Hex string `json:"hex"`
Signature string `json:"signature"`
Seal string `json:"seal"`
Name string `json:"name"`
Hex string `json:"hex"`
Signature string `json:"signature"`
Seal string `json:"seal"`
Lines []string `json:"lines"`
}
// securityContext is the context of security.json: control_commit 01…01,
// head_digest 02…02 and a round at 2030-01-01T00:00:00Z.
var securityContext = &capsule.SecurityContext{
ControlCommit: [32]byte(bytes.Repeat([]byte{1}, 32)),
HeadDigest: [32]byte(bytes.Repeat([]byte{2}, 32)),
RoundTime: time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC),
}
// SecurityContextOf reads the context of a vector file.
func SecurityContextOf(c CMSVectorContext) (*capsule.SecurityContext, error) {
cc, err1 := hex.DecodeString(c.ControlCommit)
hd, err2 := hex.DecodeString(c.HeadDigest)
rt, err3 := time.Parse(time.RFC3339, c.RoundTime)
if err := errors.Join(err1, err2, err3); err != nil || len(cc) != 32 || len(hd) != 32 {
return nil, fmt.Errorf("a context of a vector: %v", err)
}
return &capsule.SecurityContext{ControlCommit: [32]byte(cc), HeadDigest: [32]byte(hd), RoundTime: rt}, nil
}
// securityAuthorKey is the key of the signature of alg 1 that verifies in
// security.json: its seed is the SHA-256 of a text, and it is not a secret.
var securityAuthorKey = func() *authorkey.Key {
seed := sha256.Sum256([]byte("DateKeys security vector author key"))
k, err := authorkey.NewFromSeed(seed[:])
if err != nil {
panic(err)
}
return k
}()
// HeadDetail is the violation of an ERR_HEAD_INVALID of capsule.DecodeHead,
// without its prefix and its code, and "" for any other error.
func HeadDetail(err error) string {
@ -161,12 +198,20 @@ func HeadResult(b []byte) (string, string) {
return Result(err), HeadDetail(err)
}
// SecurityResult returns the verdicts of SECURITY_CBOR.
// SecurityResult returns the verdicts of SECURITY_CBOR read without the
// context of a capsule, as a reader of v0.10 reads it.
func SecurityResult(b []byte) (string, string) {
v := capsule.EvaluateSecurity(b)
return string(v.Signature), string(v.Seal)
}
// SecurityResultIn returns the verdicts of SECURITY_CBOR in the context c, and
// their lines.
func SecurityResultIn(b []byte, c *capsule.SecurityContext) (string, string, []string) {
v := capsule.EvaluateSecurityIn(b, c)
return string(v.Signature), string(v.Seal), v.Lines()
}
// check compares got with want: "*" accepts anything, and otherwise want
// is got or its start up to a ": ".
func check(what, name, got, want string) error {
@ -514,10 +559,12 @@ func mustMarshal(v any) []byte {
// SecurityVectors computes testdata/vectors/security.json, and fails if a
// vector does not get the verdicts it is written for.
func SecurityVectors() (SecurityVectorFile, error) {
c := securityContext
f := SecurityVectorFile{
Spec: SpecVersion,
Description: "SECURITY_CBOR of format 3, exactly its SECURITY_LEN bytes, and the verdicts of the signature and of the seal (spec §29.3, §29.7), " +
"generated by the reference implementation, which implements no alg and no seal_type. See testdata/README.md.",
Description: "SECURITY_CBOR of format 3, exactly its SECURITY_LEN bytes, the verdicts of the signature and of the seal in the context of the file, " +
"and their lines (spec §29.3, §29.7, §29.9). See testdata/README.md.",
Context: CMSVectorContext{ControlCommit: hex.EncodeToString(c.ControlCommit[:]), HeadDigest: hex.EncodeToString(c.HeadDigest[:]), RoundTime: c.RoundTime.Format(time.RFC3339)},
}
var errs []error
for _, v := range securityCases() {
@ -525,11 +572,11 @@ func SecurityVectors() (SecurityVectorFile, error) {
if err != nil {
return f, fmt.Errorf("security %q: %w", v.name, err)
}
sig, seal := SecurityResult(b)
sig, seal, lines := SecurityResultIn(b, c)
if sig != v.sig || seal != v.seal {
errs = append(errs, fmt.Errorf("security %q: %s and %s, want %s and %s", v.name, sig, seal, v.sig, v.seal))
}
f.Vectors = append(f.Vectors, SecurityVector{Name: v.name, Hex: hex.EncodeToString(b), Signature: sig, Seal: seal})
f.Vectors = append(f.Vectors, SecurityVector{Name: v.name, Hex: hex.EncodeToString(b), Signature: sig, Seal: seal, Lines: lines})
}
return f, errors.Join(errs...)
}
@ -548,16 +595,23 @@ func securityCases() []securityCase {
}
return m
}
// A signature of alg 1 whose sig[63] is 0x22: condition 3 of §29.9 fails.
signature := mustMarshal(map[uint64]any{0: uint64(1), 1: fill(0x11, 32), 2: append(fill(0x22, 32), fill(0x22, 32)...)})
// A signature of alg 1 that verifies in the context of the file (F4).
msg := capsule.AuthorMessage(securityContext.ControlCommit, securityContext.HeadDigest, capsule.SignersDigest(capsule.AlgEd25519, nil))
valid := mustMarshal(map[uint64]any{0: uint64(1), 1: securityAuthorKey.Public(), 2: securityAuthorKey.Sign(msg)})
seal := mustMarshal(map[uint64]any{0: uint64(1), 1: fill(0x33, 32)})
x, f0, f1, s0, s1, s2 := "X", "F0", "F1", "S0", "S1", "S2"
x, f0, f1, f2, f4, s0, s1, s2 := "X", "F0", "F1", "F2", "F4", "S0", "S1", "S2"
return []securityCase{
{"empty, as writers of this version write it", outer(), f0, s0},
{"a signature of alg 1", outer(2, signature), f1, s0},
{"a seal of seal_type 1", outer(3, seal), f0, s1},
{"a seal of seal_type 2, RFC 3161", outer(3, mustMarshal(map[uint64]any{0: uint64(2), 1: fill(0x33, 32)})), f0, s1},
{"a seal of seal_type 3, OpenTimestamps", outer(3, mustMarshal(map[uint64]any{0: uint64(3), 1: fill(0x33, 32)})), f0, s1},
{"a signature and a seal", outer(2, signature, 3, seal), f1, s1},
{"a signature of alg 1 that does not verify: its S has bits above 252", outer(2, signature), f2, s0},
{"a signature of alg 1 that verifies", outer(2, valid), f4, s0},
{"a signature of alg 4294967295, reserved for tests", outer(2, mustMarshal(map[uint64]any{0: uint64(capsule.AlgTest), 1: fill(0x11, 32), 2: fill(0x22, 64)})), f1, s0},
{"a seal of seal_type 1, reserved", outer(3, seal), f0, s1},
{"a seal of seal_type 2 whose token is not DER", outer(3, mustMarshal(map[uint64]any{0: uint64(2), 1: fill(0x33, 32)})), f0, s2},
{"a seal of seal_type 3, which no version defines", outer(3, mustMarshal(map[uint64]any{0: uint64(3), 1: fill(0x33, 32)})), f0, s1},
{"a seal of seal_type 4294967295, reserved for tests", outer(3, mustMarshal(map[uint64]any{0: uint64(capsule.SealTypeTest), 1: fill(0x33, 32)})), f0, s1},
{"a signature that does not verify and a seal of seal_type 1", outer(2, signature, 3, seal), f2, s1},
{"a signature of alg 0, and the seal intact", outer(2, mustMarshal(map[uint64]any{0: uint64(0), 1: fill(0x11, 32), 2: fill(0x22, 32)}), 3, seal), f1, s1},
{"a signature with an empty key, and the seal intact", outer(2, mustMarshal(map[uint64]any{0: uint64(1), 1: []byte{}, 2: fill(0x22, 32)}), 3, seal), f1, s1},
{"a signature that is not CBOR", outer(2, []byte{0xff}), f1, s0},

@ -24,9 +24,9 @@ import (
// Format3SpecMutations is the number of mutations of the list of format 3
// of spec §64 in the corpus, besides VERSION 4, which is "format 3: version
// changed": one for each value of a line with several, and the three cases
// changed": one for each value of a line with several, and the four cases
// that open with their verdict.
const Format3SpecMutations = 47
const Format3SpecMutations = 48
// resealPayload returns PAYLOAD_AGE of f with its plaintext replaced,
// sealed with FK_PAYLOAD and the nonce of the fixture.
@ -261,10 +261,9 @@ func format3Mutations() []Mutation {
return h + streamNonceSize + 64<<10 + 16, err
}
sigAlg1 := mustMarshal(map[uint64]any{0: uint64(1), 1: fill(0x11, 32), 2: fill(0x22, 64)})
sigAlgMax := mustMarshal(map[uint64]any{0: uint64(4294967295), 1: fill(0x11, 32), 2: fill(0x22, 64)})
sealType1 := mustMarshal(map[uint64]any{0: uint64(1), 1: fill(0x33, 32)})
sigAlgMax := mustMarshal(map[uint64]any{0: uint64(capsule.AlgTest), 1: fill(0x11, 32), 2: fill(0x22, 64)})
sealTypeMax := mustMarshal(map[uint64]any{0: uint64(capsule.SealTypeTest), 1: fill(0x33, 32)})
named := func(m Mutation, name string) Mutation { m.Name = name; return m }
notSpec := func(m Mutation) Mutation { m.Spec = false; return m }
withIdentity := func(f *LoadedFixture, in *MutationInput) (*MutationInput, error) { return f.withIdentity(in) }
relabelTK := func(e *MutationEnv) (*MutationInput, error) {
@ -379,8 +378,8 @@ func format3Mutations() []Mutation {
// with their verdicts (spec §29.3, §29.7).
named(security(securityV2(), capsule.Verdicts{Signature: capsule.VerdictUnreadable, Seal: capsule.VerdictUnreadable}), "security of version 2 opens with the verdict X"),
named(security(mustSecurity(sigAlgMax, nil), capsule.Verdicts{Signature: capsule.VerdictSignatureUnchecked, Seal: capsule.VerdictNoSeal}), "a signature of alg 4294967295 opens with the verdict F1"),
notSpec(named(security(mustSecurity(sigAlg1, nil), capsule.Verdicts{Signature: capsule.VerdictSignatureInvalid, Seal: capsule.VerdictNoSeal}), "a signature of alg 1 that does not verify opens with the verdict F2")),
named(security(mustSecurity(nil, sealType1), capsule.Verdicts{Signature: capsule.VerdictNoSignature, Seal: capsule.VerdictSealUnsupported}), "a seal of seal_type 1 opens with the verdict S1"),
named(security(mustSecurity(sigAlg1, nil), capsule.Verdicts{Signature: capsule.VerdictSignatureInvalid, Seal: capsule.VerdictNoSeal}), "a signature of alg 1 that does not verify opens with the verdict F2"),
named(security(mustSecurity(nil, sealTypeMax), capsule.Verdicts{Signature: capsule.VerdictNoSignature, Seal: capsule.VerdictSealUnsupported}), "a seal of seal_type 4294967295 opens with the verdict S1"),
// Further cases: the other relabelings of a format 3 capsule.
{Name: "format 3 time_only relabeled format 1", Want: datekeys.ErrUnsupportedVersion, Step: 14, Network: true,

@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"reflect"
"slices"
"testing"
"filippo.io/age"
@ -208,19 +209,24 @@ func TestFormat3VectorFiles(t *testing.T) {
if err := testkit.ReadJSON(dir+"security.json", &security); err != nil {
t.Fatal(err)
}
c, err := testkit.SecurityContextOf(security.Context)
if err != nil {
t.Fatal(err)
}
verdicts := map[string]bool{}
for _, v := range security.Vectors {
b, err := hex.DecodeString(v.Hex)
if err != nil {
t.Fatal(err)
}
if sig, seal := testkit.SecurityResult(b); sig != v.Signature || seal != v.Seal {
t.Errorf("security %q: %s %s, want %s %s", v.Name, sig, seal, v.Signature, v.Seal)
if sig, seal, lines := testkit.SecurityResultIn(b, c); sig != v.Signature || seal != v.Seal || !slices.Equal(lines, v.Lines) {
t.Errorf("security %q: %s %s %q, want %s %s %q", v.Name, sig, seal, lines, v.Signature, v.Seal, v.Lines)
}
verdicts[v.Signature], verdicts[v.Seal] = true, true
}
// Every verdict this version can reach has a vector.
for _, v := range []string{"X", "F0", "F1", "S0", "S1", "S2"} {
// Every verdict that needs no certificate has a vector here; those of
// alg 2 and seal_type 2 are in security_cms.json.
for _, v := range []string{"X", "F0", "F1", "F2", "F4", "S0", "S1", "S2"} {
if !verdicts[v] {
t.Errorf("no vector gives %s", v)
}

@ -4298,7 +4298,7 @@
},
{
"name": "a signature of alg 1 that does not verify opens with the verdict F2",
"spec": false,
"spec": true,
"dkc": {
"base": "format3_single.dkc",
"edits": [
@ -4326,14 +4326,14 @@
}
},
{
"name": "a seal of seal_type 1 opens with the verdict S1",
"name": "a seal of seal_type 4294967295 opens with the verdict S1",
"spec": true,
"dkc": {
"base": "format3_single.dkc",
"edits": [
[786, 6, "9c6f1f0dc845"],
[813, 41, "21d7830f993c91aab8abf294f1265c148a22d3631a140ed44ae7be80b8383d3408fc6d9b9a02f9146a"],
[1547, 16, "246b17f7819778da6111cf3e50d993ba"]
[786, 6, "e06f1f0dc845"],
[813, 45, "21d78f0f99276f0d6767c0ffe2265c148a22d3631a140ed44ae7be80b8383d3408fc6d9b9a02f9146a04a75294"],
[1547, 16, "8731c709cc638cee980df229ab30e569"]
]
},
"release": {

@ -1,132 +1,237 @@
{
"spec": "0.11",
"description": "SECURITY_CBOR of format 3, exactly its SECURITY_LEN bytes, and the verdicts of the signature and of the seal (spec §29.3, §29.7), generated by the reference implementation, which implements no alg and no seal_type. See testdata/README.md.",
"description": "SECURITY_CBOR of format 3, exactly its SECURITY_LEN bytes, the verdicts of the signature and of the seal in the context of the file, and their lines (spec §29.3, §29.7, §29.9). See testdata/README.md.",
"context": {
"control_commit": "0101010101010101010101010101010101010101010101010101010101010101",
"head_digest": "0202020202020202020202020202020202020202020202020202020202020202",
"round_time": "2030-01-01T00:00:00Z"
},
"vectors": [
{
"name": "empty, as writers of this version write it",
"hex": "a20071646174656b6579732d73656375726974790101",
"signature": "F0",
"seal": "S0"
"seal": "S0",
"lines": [
"Sin firma de autor."
]
},
{
"name": "a signature of alg 1",
"name": "a signature of alg 1 that does not verify: its S has bits above 252",
"hex": "a30071646174656b6579732d73656375726974790101025869a30001015820111111111111111111111111111111111111111111111111111111111111111102584022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222",
"signature": "F2",
"seal": "S0",
"lines": [
"La firma no corresponde a este contenido."
]
},
{
"name": "a signature of alg 1 that verifies",
"hex": "a30071646174656b6579732d73656375726974790101025869a30001015820c1f26f2fe7a8b5046cadaea50cfd6f1c9eba22a77d964d84cdc9843d98057a0902584099e44f44384abbffd3c0853ce1b3841b89f0677152342210b619c1612707f11fe3b1213d135030fecf018f0c06aa7bc4b170028be79038cf5abd2c3d2ff39900",
"signature": "F4",
"seal": "S0",
"lines": [
"Firmado con la clave dkauthor1c8ex7tl84z6sgm9d46jselt0rj0t5g480ktympxdexzrmxq90gysk64cx5. No prueba quién la tiene."
]
},
{
"name": "a signature of alg 4294967295, reserved for tests",
"hex": "a30071646174656b6579732d7365637572697479010102586da3001affffffff015820111111111111111111111111111111111111111111111111111111111111111102584022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222",
"signature": "F1",
"seal": "S0"
"seal": "S0",
"lines": [
"No se ha comprobado ninguna firma: trátala como no firmada."
]
},
{
"name": "a seal of seal_type 1",
"name": "a seal of seal_type 1, reserved",
"hex": "a30071646174656b6579732d73656375726974790101035826a200010158203333333333333333333333333333333333333333333333333333333333333333",
"signature": "F0",
"seal": "S1"
"seal": "S1",
"lines": [
"Sin firma de autor.",
"Lleva un sello de tiempo que esta versión no sabe comprobar: aquí no prueba nada."
]
},
{
"name": "a seal of seal_type 2, RFC 3161",
"name": "a seal of seal_type 2 whose token is not DER",
"hex": "a30071646174656b6579732d73656375726974790101035826a200020158203333333333333333333333333333333333333333333333333333333333333333",
"signature": "F0",
"seal": "S1"
"seal": "S2",
"lines": [
"Sin firma de autor.",
"El sello de tiempo es ilegible: no prueba nada."
]
},
{
"name": "a seal of seal_type 3, OpenTimestamps",
"name": "a seal of seal_type 3, which no version defines",
"hex": "a30071646174656b6579732d73656375726974790101035826a200030158203333333333333333333333333333333333333333333333333333333333333333",
"signature": "F0",
"seal": "S1"
"seal": "S1",
"lines": [
"Sin firma de autor.",
"Lleva un sello de tiempo que esta versión no sabe comprobar: aquí no prueba nada."
]
},
{
"name": "a signature and a seal",
"name": "a seal of seal_type 4294967295, reserved for tests",
"hex": "a30071646174656b6579732d7365637572697479010103582aa2001affffffff0158203333333333333333333333333333333333333333333333333333333333333333",
"signature": "F0",
"seal": "S1",
"lines": [
"Sin firma de autor.",
"Lleva un sello de tiempo que esta versión no sabe comprobar: aquí no prueba nada."
]
},
{
"name": "a signature that does not verify and a seal of seal_type 1",
"hex": "a40071646174656b6579732d73656375726974790101025869a30001015820111111111111111111111111111111111111111111111111111111111111111102584022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222035826a200010158203333333333333333333333333333333333333333333333333333333333333333",
"signature": "F1",
"seal": "S1"
"signature": "F2",
"seal": "S1",
"lines": [
"La firma no corresponde a este contenido.",
"Lleva un sello de tiempo que esta versión no sabe comprobar: aquí no prueba nada."
]
},
{
"name": "a signature of alg 0, and the seal intact",
"hex": "a40071646174656b6579732d73656375726974790101025849a3000001582011111111111111111111111111111111111111111111111111111111111111110258202222222222222222222222222222222222222222222222222222222222222222035826a200010158203333333333333333333333333333333333333333333333333333333333333333",
"signature": "F1",
"seal": "S1"
"seal": "S1",
"lines": [
"No se ha comprobado ninguna firma: trátala como no firmada.",
"Lleva un sello de tiempo que esta versión no sabe comprobar: aquí no prueba nada."
]
},
{
"name": "a signature with an empty key, and the seal intact",
"hex": "a40071646174656b6579732d73656375726974790101025828a3000101400258202222222222222222222222222222222222222222222222222222222222222222035826a200010158203333333333333333333333333333333333333333333333333333333333333333",
"signature": "F1",
"seal": "S1"
"seal": "S1",
"lines": [
"No se ha comprobado ninguna firma: trátala como no firmada.",
"Lleva un sello de tiempo que esta versión no sabe comprobar: aquí no prueba nada."
]
},
{
"name": "a signature that is not CBOR",
"hex": "a30071646174656b6579732d736563757269747901010241ff",
"signature": "F1",
"seal": "S0"
"seal": "S0",
"lines": [
"No se ha comprobado ninguna firma: trátala como no firmada."
]
},
{
"name": "a signature with a byte more",
"hex": "a30071646174656b6579732d7365637572697479010102586aa3000101582011111111111111111111111111111111111111111111111111111111111111110258402222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222200",
"signature": "F1",
"seal": "S0"
"seal": "S0",
"lines": [
"No se ha comprobado ninguna firma: trátala como no firmada."
]
},
{
"name": "a seal of seal_type 0",
"hex": "a30071646174656b6579732d73656375726974790101035826a200000158203333333333333333333333333333333333333333333333333333333333333333",
"signature": "F0",
"seal": "S2"
"seal": "S2",
"lines": [
"Sin firma de autor.",
"El sello de tiempo es ilegible: no prueba nada."
]
},
{
"name": "a seal that breaks its schema, with an unknown seal_type",
"hex": "a30071646174656b6579732d73656375726974790101035829a300186301582033333333333333333333333333333333333333333333333333333333333333330200",
"signature": "F0",
"seal": "S2"
"seal": "S2",
"lines": [
"Sin firma de autor.",
"El sello de tiempo es ilegible: no prueba nada."
]
},
{
"name": "a seal that is not CBOR",
"hex": "a30071646174656b6579732d736563757269747901010341ff",
"signature": "F0",
"seal": "S2"
"seal": "S2",
"lines": [
"Sin firma de autor.",
"El sello de tiempo es ilegible: no prueba nada."
]
},
{
"name": "key 2 that is not a byte string",
"hex": "a30071646174656b6579732d7365637572697479010102a10001",
"signature": "X",
"seal": "X"
"seal": "X",
"lines": [
"No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada."
]
},
{
"name": "key 2 that is an empty byte string",
"hex": "a30071646174656b6579732d736563757269747901010240",
"signature": "X",
"seal": "X"
"seal": "X",
"lines": [
"No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada."
]
},
{
"name": "an unknown key 4",
"hex": "a30071646174656b6579732d73656375726974790101044101",
"signature": "X",
"seal": "X"
"seal": "X",
"lines": [
"No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada."
]
},
{
"name": "a byte more after the map",
"hex": "a20071646174656b6579732d7365637572697479010100",
"signature": "X",
"seal": "X"
"seal": "X",
"lines": [
"No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada."
]
},
{
"name": "version 2",
"hex": "a20071646174656b6579732d73656375726974790102",
"signature": "X",
"seal": "X"
"seal": "X",
"lines": [
"No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada."
]
},
{
"name": "the type tag of the head",
"hex": "a2006d646174656b6579732d686561640101",
"signature": "X",
"seal": "X"
"seal": "X",
"lines": [
"No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada."
]
},
{
"name": "keys 2 and 3 out of order",
"hex": "a40071646174656b6579732d73656375726974790101035826a200010158203333333333333333333333333333333333333333333333333333333333333333025869a30001015820111111111111111111111111111111111111111111111111111111111111111102584022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222",
"signature": "X",
"seal": "X"
"seal": "X",
"lines": [
"No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada."
]
},
{
"name": "an array",
"hex": "8271646174656b6579732d736563757269747901",
"signature": "X",
"seal": "X"
"seal": "X",
"lines": [
"No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada."
]
}
]
}

Loading…
Cancel
Save

Powered by TurnKey Linux.