Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
package capsule
import (
"encoding/binary"
"fmt"
"strings"
"time"
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
datekeys "g.activething.com/go/DateKeys"
"g.activething.com/go/DateKeys/codec"
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
"g.activething.com/go/DateKeys/codec/bech32"
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
"g.activething.com/go/DateKeys/extension"
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
"g.activething.com/go/DateKeys/internal/cms"
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
"g.activething.com/go/DateKeys/internal/pathrule"
)
// The content of a format 3 capsule (spec §29.2): the plaintext of
// PAYLOAD_AGE is BODY followed by its padding, and BODY is a frame of 12
// bytes, the security area, the head and the files.
const (
// BodyFrameSize is the size of the frame of BODY: AREA_LEN, SECURITY_LEN
// and HEAD_LEN, three unsigned 32-bit big-endian integers.
BodyFrameSize = 12
// AreaUnit is the unit of AREA_LEN, and MaxAreaLen its maximum.
AreaUnit = 512
MaxAreaLen = 128 * AreaUnit
// AreaLen is the size of the security area that writers of this version
// write, always, whatever the capsule holds (spec v0.11, §29.2, §62.1
// rule 13): 32 KiB. Writers of v0.10 wrote AreaUnit, 512 bytes.
AreaLen = 64 * AreaUnit
// LargeAreaLen is the area of a capsule whose creator expressly asked for
// a larger one because the signatures do not fit in AreaLen: 64 KiB.
LargeAreaLen = MaxAreaLen
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
// MaxHeadLen is the maximum of HEAD_LEN, 16 MiB.
MaxHeadLen = 16 << 20
SecurityTypeTag = "datekeys-security"
SecurityVersion = 1
HeadTypeTag = "datekeys-head"
HeadVersion = 1
// SaltSize is the size of the salt of the head (spec §29.4).
SaltSize = 32
// Limits of the head, fixed with format 3 (spec §29.4).
MaxCommentLen = pathrule . MaxCommentLen
MaxAuthorLen = pathrule . MaxAuthorLen
MaxFiles = 65535
MaxPathLen = pathrule . MaxPathLen
// MaxMTime is 9999-12-31T23:59:59Z in seconds since 1970-01-01 UTC.
MaxMTime = 253402300799
// maxSecurityItem bounds the byte strings of keys 2 and 3 of security.
maxSecurityItem = 65536
// maxAlg bounds alg and seal_type.
maxAlg = 1 << 32 - 1
)
// BodyFrame is the frame of BODY (spec §29.2).
type BodyFrame struct {
AreaLen , SecurityLen , HeadLen uint32
}
// Bytes returns the 12 bytes of the frame.
func ( f BodyFrame ) Bytes ( ) [ BodyFrameSize ] byte {
var b [ BodyFrameSize ] byte
binary . BigEndian . PutUint32 ( b [ 0 : ] , f . AreaLen )
binary . BigEndian . PutUint32 ( b [ 4 : ] , f . SecurityLen )
binary . BigEndian . PutUint32 ( b [ 8 : ] , f . HeadLen )
return b
}
// ContentLength is C, the length of CONTENT in a BODY of length l whose frame
// is f. ParseBodyFrame has checked that it does not underflow.
func ( f BodyFrame ) ContentLength ( l uint64 ) uint64 {
return l - BodyFrameSize - uint64 ( f . AreaLen ) - uint64 ( f . HeadLen )
}
// ParseBodyFrame decodes the frame of BODY from its first 12 bytes and checks
// it against L, the length of BODY (spec §29.2, §63 step 17.2). Every
// violation is ErrIntegrity. The plaintext of PAYLOAD_AGE is at least 256
// bytes, so the 12 bytes exist even when L is shorter than the frame.
func ParseBodyFrame ( b [ ] byte , l uint64 ) ( BodyFrame , error ) {
if len ( b ) != BodyFrameSize {
return BodyFrame { } , fmt . Errorf ( "capsule: BODY: frame of %d bytes, want %d" , len ( b ) , BodyFrameSize )
}
if l < BodyFrameSize {
return BodyFrame { } , fmt . Errorf ( "capsule: BODY: L = %d is shorter than the frame of %d bytes: %w" , l , BodyFrameSize , datekeys . ErrIntegrity )
}
f := BodyFrame {
AreaLen : binary . BigEndian . Uint32 ( b [ 0 : ] ) ,
SecurityLen : binary . BigEndian . Uint32 ( b [ 4 : ] ) ,
HeadLen : binary . BigEndian . Uint32 ( b [ 8 : ] ) ,
}
switch {
case f . AreaLen < AreaUnit || f . AreaLen > MaxAreaLen || f . AreaLen % AreaUnit != 0 :
return f , fmt . Errorf ( "capsule: BODY: AREA_LEN %d is not a multiple of %d from %d to %d: %w" , f . AreaLen , AreaUnit , AreaUnit , MaxAreaLen , datekeys . ErrIntegrity )
case f . SecurityLen < 1 || f . SecurityLen > f . AreaLen :
return f , fmt . Errorf ( "capsule: BODY: SECURITY_LEN %d is not from 1 to AREA_LEN = %d: %w" , f . SecurityLen , f . AreaLen , datekeys . ErrIntegrity )
case f . HeadLen < 1 || f . HeadLen > MaxHeadLen :
return f , fmt . Errorf ( "capsule: BODY: HEAD_LEN %d is not from 1 to %d: %w" , f . HeadLen , MaxHeadLen , datekeys . ErrIntegrity )
case BodyFrameSize + uint64 ( f . AreaLen ) + uint64 ( f . HeadLen ) > l :
return f , fmt . Errorf ( "capsule: BODY: the frame, the area of %d bytes and the head of %d bytes exceed L = %d: %w" , f . AreaLen , f . HeadLen , l , datekeys . ErrIntegrity )
}
return f , nil
}
// CheckArea checks that the bytes of the security area after SECURITY_CBOR,
// its first securityLen bytes, are zero (spec §29.2): ErrIntegrity if not.
func CheckArea ( area [ ] byte , securityLen uint32 ) error {
for i , c := range area [ securityLen : ] {
if c != 0 {
return fmt . Errorf ( "capsule: BODY: byte %d of the security area is not zero: %w" , int ( securityLen ) + i , datekeys . ErrIntegrity )
}
}
return nil
}
// Verdict is the result of evaluating the signature or the seal of the
// security area (spec §29.7). A verdict never prevents opening.
type Verdict string
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// The verdicts of a reader (spec v0.11, §29.7). A reader of v0.10 reaches
// X, F0, F1, S0, S1 and S2 only.
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
const (
// VerdictUnreadable (X): security fails its layer 2 or 3; it stands for
// both the signature and the seal.
VerdictUnreadable Verdict = "X"
// VerdictNoSignature (F0): no key 2.
VerdictNoSignature Verdict = "F0"
// VerdictSignatureUnchecked (F1): a signature that does not decode, breaks
// its schema or has an alg this reader does not implement.
VerdictSignatureUnchecked Verdict = "F1"
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// VerdictSignatureInvalid (F2): a signature present that does not verify.
VerdictSignatureInvalid Verdict = "F2"
// VerdictSignedSaved (F3): a valid signature of alg 1 with a key the
// person saved, whose label Verdicts.AuthorLabel holds.
VerdictSignedSaved Verdict = "F3"
// VerdictSignedOther (F4): a valid signature of alg 1 with another key,
// which Verdicts.AuthorKey holds. It does not prove who holds it.
VerdictSignedOther Verdict = "F4"
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
// VerdictNoSeal (S0): no key 3; nothing is shown about the date.
VerdictNoSeal Verdict = "S0"
// VerdictSealUnsupported (S1): a seal_type this reader does not implement.
VerdictSealUnsupported Verdict = "S1"
// VerdictSealUnreadable (S2): a seal that does not decode or breaks its
// schema.
VerdictSealUnreadable Verdict = "S2"
// VerdictSignedIncomplete (F5): a signature of alg 2 with a required
// signer absent, not verifiable, without a seal or with an invalid one or
// out of validity, or with a key 3 (spec v0.11, §29.10).
VerdictSignedIncomplete Verdict = "F5"
// VerdictSignedComplete (F6): a signature of alg 2 with every required
// signer valid and sealed. Verdicts.Detail names them.
VerdictSignedComplete Verdict = "F6"
// VerdictSealInvalid (S3): a seal that does not verify.
VerdictSealInvalid Verdict = "S3"
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
// VerdictSealed (S4): a valid seal with accuracy and t + accuracy <
// round_time (spec v0.16, §29.11).
VerdictSealed Verdict = "S4"
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
// VerdictSealedLate (S5): a valid seal that does not prove that it came
// before round_time. Detail.SealReason says why.
VerdictSealedLate Verdict = "S5"
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
)
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
// SealReason is why a valid seal does not prove that it came before the
// opening date (spec v0.16, §29.7): the reason of S5, and of the line of a
// signer of F6 that does not say «antes de la fecha de apertura».
type SealReason string
const (
// ReasonNone: the seal proves it (S4, or the line of a signer that says
// so).
ReasonNone SealReason = ""
// ReasonLate: t plus the accuracy, 0 without one, is not before
// round_time.
ReasonLate SealReason = "late"
// ReasonNoAccuracyBTSP: the token carries no accuracy, and its policy is
// the BTSP of ETSI EN 319 421, which requires it.
ReasonNoAccuracyBTSP SealReason = "no accuracy, BTSP"
// ReasonNoAccuracy: the token carries no accuracy.
ReasonNoAccuracy SealReason = "no accuracy"
)
// Text is the reason as the texts of §29.7 write it, "" for ReasonNone.
func ( r SealReason ) Text ( ) string {
switch r {
case ReasonLate :
return "se selló después de esa fecha o demasiado cerca de ella"
case ReasonNoAccuracyBTSP :
return "el sello no dice la precisión que exige su política"
case ReasonNoAccuracy :
return "el sello no dice su precisión"
}
return ""
}
// sealReason is the reason of a token that verifies, the first that holds
// (spec v0.16, §29.7): late, then without accuracy under BTSP, then without
// accuracy; ReasonNone when it proves that it came before roundTime.
func sealReason ( tok * cms . Token , roundTime time . Time ) SealReason {
switch {
case roundTime . IsZero ( ) || ! tok . GenTime . Add ( tok . Accuracy ) . Before ( roundTime ) :
return ReasonLate
case ! tok . HasAccuracy && tok . BTSP ( ) :
return ReasonNoAccuracyBTSP
case ! tok . HasAccuracy :
return ReasonNoAccuracy
}
return ReasonNone
}
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
// Text returns the text of the verdict that the official SDK shows, in
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// Spanish (spec §29.7), and "" for S0, which shows nothing, and for the
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
// verdicts whose text names a key or a reason, which Verdicts.Lines writes.
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
func ( v Verdict ) Text ( ) string {
switch v {
case VerdictUnreadable :
return "No se han podido comprobar la firma ni el sello: trátala como no firmada y sin fecha probada."
case VerdictNoSignature :
return "Sin firma de autor."
case VerdictSignatureUnchecked :
return "No se ha comprobado ninguna firma: trátala como no firmada."
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
case VerdictSignatureInvalid :
return "La firma no corresponde a este contenido."
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
case VerdictSealUnsupported :
return "Lleva un sello de tiempo que esta versión no sabe comprobar: aquí no prueba nada."
case VerdictSealUnreadable :
return "El sello de tiempo es ilegible: no prueba nada."
case VerdictSignedIncomplete :
return "Faltan firmas o sellos que la propia cápsula exige: trátala como no firmada."
case VerdictSealInvalid :
return "El sello no corresponde a este contenido."
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
}
return ""
}
// Verdicts are the verdicts of the security area of a format 3 capsule.
type Verdicts struct {
Signature , Seal Verdict
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// AuthorKey is the public key of a valid signature of alg 1 (F3, F4).
AuthorKey [ 32 ] byte
// AuthorLabel is the label of the saved key that signed (F3).
AuthorLabel string
// Detail names the signers of an alg 2 signature and the authority of a
// valid seal; nil otherwise. A pointer, so that Verdicts stays comparable.
Detail * Detail
}
// Detail is what the texts of F6, S4 and S5 name (spec v0.11, §29.7, §29.10).
type Detail struct {
// Signers are the required signers, in the order of SIGNERS, and Foreign
// the SignerInfo of other certificates, which never count.
Signers , Foreign [ ] SignerLine
// SealHolder and SealTime are the holder of the certificate of the
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
// authority of a valid seal, as §29.7 writes it, and t. SealReason is
// why it does not prove that it came before round_time (S5).
SealHolder string
SealTime time . Time
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
SealReason SealReason
}
// SignerLine is a signer of an alg 2 signature.
type SignerLine struct {
// Holder is the name of the certificate as §29.7 shows it: the subject,
// or the SHA-256 of the certificate in hexadecimal when it does not meet
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// the rules of a name of a certificate.
Holder string
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// Issuer is the issuer that the certificate says, with the same rules.
Issuer string
// Result is "valid", "invalid", "absent", "not verifiable", "without
// seal", "invalid seal" or "out of validity".
Result string
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// SealHolder is the holder of the certificate of the authority of its
// seal, and SealTime t, both zero without a seal that verifies. Before is
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
// true when the seal proves that it came before round_time: it carries
// accuracy and t plus the accuracy is before round_time (spec v0.16,
// §29.11); Reason says why not, for a valid signer.
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
SealHolder string
SealTime time . Time
Before bool
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
Reason SealReason
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
}
// resultText is the result of a signer in the texts of §29.7.
var resultText = map [ string ] string {
"valid" : "válida" ,
"invalid" : "inválida" ,
"absent" : "ausente" ,
"not verifiable" : "no verificable" ,
"without seal" : "sin sello" ,
"invalid seal" : "con el sello inválido" ,
"out of validity" : "con el certificado fuera de validez" ,
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
}
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// quoted puts a name of a certificate between « and », as the texts of §29.7
// write it, so that where it starts and where it ends is in view.
func quoted ( name string ) string { return "«" + name + "»" }
// instant writes t in UTC as §29.7 shows it: RFC 3339, with the fraction of
// the seal when it has one.
func instant ( t time . Time ) string { return t . UTC ( ) . Format ( time . RFC3339Nano ) }
Spec v0.11 approved: the text of the review, SpecVersion 0.11 and its SHA-256
The author approved the text and the six open decisions on 1 October 2026.
The spec says now what the review left open: the form of the CMS signature
and of the TSTInfo field by field, the ESSCertIDv2 with SHA-256 written, the
padding of the locator at its boundaries, base32 CIDs, the addresses read
without decoding, the issuer shown by the rules of the holder, and the area
decided after the signatures. SpecVersion is 0.11, the records of fixtures
and vectors say so, and decrypt shows an mtime later than a valid seal as an
inconsistency, which 29.7 asks as a SHOULD.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
6 days ago
// SealedAt returns the earliest instant that a valid seal gives, the seal of
// key 3 or that of a required signer of an alg 2 signature, and false when
// there is none (spec v0.11, §29.7). A reader shows an mtime later than it as
// an inconsistency: whoever made the capsule claims a file that is newer than
// the proof that it existed.
func ( v Verdicts ) SealedAt ( ) ( time . Time , bool ) {
var best time . Time
take := func ( t time . Time ) {
if ! t . IsZero ( ) && ( best . IsZero ( ) || t . Before ( best ) ) {
best = t
}
}
if v . Detail != nil {
if v . Seal == VerdictSealed || v . Seal == VerdictSealedLate {
take ( v . Detail . SealTime )
}
for _ , s := range v . Detail . Signers {
if s . Result == "valid" {
take ( s . SealTime )
}
}
}
return best , ! best . IsZero ( )
}
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
// Lines are the verdicts as the official SDK shows them, in order: X alone,
// or the signature and then the seal, when it shows something.
func ( v Verdicts ) Lines ( ) [ ] string {
if v . Signature == VerdictUnreadable {
return [ ] string { VerdictUnreadable . Text ( ) }
}
lines := [ ] string { v . Signature . Text ( ) }
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
switch v . Signature {
case VerdictSignedSaved :
lines [ 0 ] = "Firmado con la clave que guardaste como " + v . AuthorLabel + "."
case VerdictSignedOther :
key , _ := bech32 . Encode ( "dkauthor" , v . AuthorKey [ : ] )
lines [ 0 ] = "Firmado con la clave " + key + ". No prueba quién la tiene."
}
if v . Signature == VerdictSignedComplete && v . Detail != nil {
names := make ( [ ] string , len ( v . Detail . Signers ) )
for i , s := range v . Detail . Signers {
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
names [ i ] = quoted ( s . Holder )
}
lines [ 0 ] = "Firmado con un certificado a nombre de " + strings . Join ( names , ", " ) +
". DateKeys no comprueba quién lo emitió: para eso, exporta la firma a un validador oficial."
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
before := false
for _ , s := range v . Detail . Signers {
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
when := "sin acreditar que fuera antes de la fecha de apertura: " + s . Reason . Text ( )
if s . Before {
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
when , before = "antes de la fecha de apertura" , true
}
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
lines = append ( lines , fmt . Sprintf ( " %s (emisor según su certificado: %s), sellado por %s el %s, %s." , quoted ( s . Holder ) , quoted ( s . Issuer ) , quoted ( s . SealHolder ) , instant ( s . SealTime ) , when ) )
}
// §29.7: whoever says that a capsule was signed before the date says
// that it does not check who issued the seal.
if before {
lines = append ( lines , " DateKeys no comprueba quién emitió los sellos." )
}
}
if v . Detail != nil {
for _ , s := range v . Detail . Foreign {
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
lines = append ( lines , fmt . Sprintf ( " Otro firmante, %s: %s. No cuenta." , quoted ( s . Holder ) , resultText [ s . Result ] ) )
}
}
switch t := v . Seal . Text ( ) ; {
case v . Seal == VerdictSealed && v . Detail != nil :
Spec v0.12 draft and the verdicts of a certificate (not approved)
The draft v0.12 fixes what the review of the implementation of v0.11
found, without changing any format: the names of certificates in the
verdicts, the seal of each signer in the lines of F6 with the warning that
nobody checks who issued it, the holder by givenName and surname before
the commonName that carries the NIF, a profile of the certificate field by
field, identifiers by their bytes, repeated elements of a SET OF, the
edge cases of the token, the addresses and the padding of the locator, and
the errata of 44.1, 55.2, 64, 67 and 76. Section 76 lists each change with
its case. The CDDL fixes the sizes of the locator.
The reader shows the names of certificates between quotes, refuses one of
more than 64 code points or with two spaces in a row, names the authority
of each seal of F6 and adds the warning when a line says before the date,
and writes the result of a foreign signer in Spanish. The records of
format3_signed_cms and format3_sealed follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
lines = append ( lines , "Según un sello a nombre de " + quoted ( v . Detail . SealHolder ) + ", existía el " + instant ( v . Detail . SealTime ) +
", antes de que la cápsula pudiera abrirse. DateKeys no comprueba quién emitió el sello." )
v0.16: a seal without accuracy proves nothing before the opening date
A valid seal is S4 only when its token carries accuracy and t plus the
accuracy is before round_time; otherwise S5, whose text gives the reason,
the first that holds: sealed after or too close, no accuracy under the BTSP
policy of ETSI EN 319 421 (0.4.0.2023.1.1), or no accuracy (spec v0.16,
29.7, 29.11). The line of a signer of F6 whose seal does not prove it says
so with the same reason. cms.Token gains HasAccuracy, Policy and BTSP;
Verdicts gain SealReason and SignerLine.Reason; EncryptFiles returns the
verdicts of the area it wrote in Result.Security, so that a writer warns of
a seal without accuracy (rule 19).
security_cms.json is made again: 143 cases, the seals about something else
with an accuracy of a second, and the new cases of 64 with seal_reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 hours ago
case v . Seal == VerdictSealedLate && v . Detail != nil :
lines = append ( lines , "No acredita que se sellara antes de la fecha de apertura: " + v . Detail . SealReason . Text ( ) + "." )
case t != "" :
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
lines = append ( lines , t )
}
return lines
}
// securityWire is the outer map of SECURITY_CBOR: keys 2 and 3 hold
// separately encoded CBOR (spec §29.3).
type securityWire struct {
signature , seal [ ] byte // nil when absent
}
func ( w * securityWire ) encode ( e * codec . Encoder ) {
n := 2
if w . signature != nil {
n ++
}
if w . seal != nil {
n ++
}
e . Map ( n )
e . Uint ( 0 )
e . Text ( SecurityTypeTag )
e . Uint ( 1 )
e . Uint ( SecurityVersion )
if w . signature != nil {
e . Uint ( 2 )
e . Bstr ( w . signature )
}
if w . seal != nil {
e . Uint ( 3 )
e . Bstr ( w . seal )
}
}
func ( w * securityWire ) decode ( d * codec . Decoder ) error {
pairs , err := d . Map ( 4 )
if err != nil {
return err
}
var seen uint
for range pairs {
k , err := d . Key ( )
if err != nil {
return err
}
switch k {
case 0 :
_ , err = d . Text ( len ( SecurityTypeTag ) )
case 1 :
_ , err = d . Uint ( SecurityVersion )
case 2 :
w . signature , err = d . Bstr ( 1 , maxSecurityItem )
case 3 :
w . seal , err = d . Bstr ( 1 , maxSecurityItem )
default :
return fmt . Errorf ( "key %d is not defined: %w" , k , datekeys . ErrNonCanonicalCBOR )
}
if err != nil {
return fmt . Errorf ( "key %d: %w" , k , err )
}
seen |= 1 << k
}
if err := required ( seen , 2 ) ; err != nil {
return err
}
return d . EndMap ( )
}
// EncodeSecurity returns SECURITY_CBOR as a writer of this version writes it:
// empty, {0: "datekeys-security", 1: 1}, 22 bytes (spec §29.3).
func EncodeSecurity ( ) [ ] byte {
var e codec . Encoder
( & securityWire { } ) . encode ( & e )
b , _ := e . Out ( )
return b
}
// EncodeSecurityWith returns SECURITY_CBOR with the given contents of keys 2
Docs at spec v0.11 and the draft v0.12: READMEs, SECURITY, traceability, CHANGELOG
The session that closed v0.11 left the documentation at v0.10 (review of
2 October, G14).
- README.md and README.es.md say the same again: the reference implements
v0.11, tagged, and the branch v0.12 the draft; SpecVersion 0.11; the area
of 32 KiB in the picture of BODY; the table of modules with authorkey,
internal/cms, internal/der, locator, wordkey and the public note; and what
the CLI does now: encrypt -sign shows the key and the code of
AUTHOR_MESSAGE before it signs, decrypt -expect-author writes nothing
unless the key of an F4 matches, the lines of the verdicts break behind a
mark, and decrypt and inspect say when a public note is not shown. The
security properties no longer say that no signature is checked.
- SECURITY.md: the scope is v0.11 and the draft v0.12; the limits of a
signature, a seal and a key of words; the standard library among the
cryptographic dependencies.
- docs/traceability.md at the draft v0.12: rows for 24.1, 29.8 to 29.12,
38.1 and 44.1, and rows 29.2, 29.3, 29.7, 62.1, 64, 67, 70, 72 and 76 up
to date, with the code and the tests of each. The cases of spec 64 that
security_cms.json and locator.json still lack are marked pending.
- CHANGELOG.md: an entry for the draft v0.12: the review and its fixes, the
draft, the CMS reader with its own profile, the addresses of the locator,
the CLI, the new test data, and what is pending.
- capsule/format3.go: the comments of EncodeSecurityWith,
EncodeAuthorSignature and EncodeSeal no longer say that this version
defines no alg and no seal_type.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// and 3, nil when absent (spec §29.3). EncryptFiles writes it with what this
// version defines, a signature of alg 1 or 2 and a seal of seal_type 2; any
// other content only a generator of test vectors writes (spec §62.1 rule 13).
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
func EncodeSecurityWith ( signature , seal [ ] byte ) ( [ ] byte , error ) {
var e codec . Encoder
( & securityWire { signature : signature , seal : seal } ) . encode ( & e )
return e . Out ( )
}
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// EvaluateSecurity reads SECURITY_CBOR and returns its verdicts without the
// capsule around it (spec §29.3, §29.7), as a reader of v0.10 does: it checks
// the structure, and any signature is F1. EvaluateSecurityIn checks the
// signature too. It never fails: security never decides the opening. For the
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
// signature and for the seal apart, the first row of the table of §29.7 that
// holds decides: alg and seal_type are read only from content that decodes
// and meets its schema.
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
func EvaluateSecurity ( b [ ] byte ) Verdicts { return EvaluateSecurityIn ( b , nil ) }
// decodeSecurity decodes the outer map of SECURITY_CBOR, layers 2 and 3.
func decodeSecurity ( b [ ] byte ) ( * securityWire , bool ) {
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
if tag , version , err := codec . Peek ( b ) ; err != nil || tag != SecurityTypeTag || version != SecurityVersion {
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
return nil , false
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
}
var w securityWire
if err := codec . Unmarshal ( b , w . decode , w . encode ) ; err != nil {
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
return nil , false
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
}
Signature plan, steps 3 and 4 begun: what is signed and the verdicts of alg 1
capsule/signature.go has what an author signs and a seal seals, as the
spec v0.11 draft defines it (29.8, 29.11): payload_commit, control_commit
over CONTROL_SIG, without I_PAYLOAD and with L at zero, head_digest,
signers_digest, AUTHOR_MESSAGE as ASCII text of 99 bytes with its code,
SIG_PART over the exact content of key 2, and SEAL_SUBJECT.
EvaluateSecurityIn checks a signature of alg 1 with the strict profile in
the context of a capsule: F4, or F3 with a key the person saved; F2 when
it does not verify; F1 without context, as in v0.10, and for alg 2, not
yet implemented. Verdicts carries the key and the label for the texts.
Not wired yet: the writer does not sign and still writes the area of 512
bytes, and the reader still calls EvaluateSecurity without context. The
handoff of docs lists what is left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
return & w , true
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
}
// authorSignature is the content of key 2 of security: {0: alg, 1: public
// key, 2: signature} (spec §29.3).
type authorSignature struct {
alg uint64
key , value [ ] byte
}
func ( a * authorSignature ) encode ( e * codec . Encoder ) {
e . Map ( 3 )
e . Uint ( 0 )
e . Uint ( a . alg )
e . Uint ( 1 )
e . Bstr ( a . key )
e . Uint ( 2 )
e . Bstr ( a . value )
}
func ( a * authorSignature ) decode ( d * codec . Decoder ) error {
return decodeItem ( d , 3 , func ( k uint64 ) ( err error ) {
switch k {
case 0 :
a . alg , err = decodeAlg ( d )
case 1 :
a . key , err = d . Bstr ( 0 , maxSecurityItem )
case 2 :
a . value , err = d . Bstr ( 0 , maxSecurityItem )
default :
err = fmt . Errorf ( "key %d is not defined: %w" , k , datekeys . ErrNonCanonicalCBOR )
}
return err
} )
}
// decodeAuthorSignature decodes the content of key 2 of security.
func decodeAuthorSignature ( b [ ] byte ) ( * authorSignature , error ) {
var a authorSignature
if err := codec . Unmarshal ( b , a . decode , a . encode ) ; err != nil {
return nil , err
}
return & a , nil
}
Docs at spec v0.11 and the draft v0.12: READMEs, SECURITY, traceability, CHANGELOG
The session that closed v0.11 left the documentation at v0.10 (review of
2 October, G14).
- README.md and README.es.md say the same again: the reference implements
v0.11, tagged, and the branch v0.12 the draft; SpecVersion 0.11; the area
of 32 KiB in the picture of BODY; the table of modules with authorkey,
internal/cms, internal/der, locator, wordkey and the public note; and what
the CLI does now: encrypt -sign shows the key and the code of
AUTHOR_MESSAGE before it signs, decrypt -expect-author writes nothing
unless the key of an F4 matches, the lines of the verdicts break behind a
mark, and decrypt and inspect say when a public note is not shown. The
security properties no longer say that no signature is checked.
- SECURITY.md: the scope is v0.11 and the draft v0.12; the limits of a
signature, a seal and a key of words; the standard library among the
cryptographic dependencies.
- docs/traceability.md at the draft v0.12: rows for 24.1, 29.8 to 29.12,
38.1 and 44.1, and rows 29.2, 29.3, 29.7, 62.1, 64, 67, 70, 72 and 76 up
to date, with the code and the tests of each. The cases of spec 64 that
security_cms.json and locator.json still lack are marked pending.
- CHANGELOG.md: an entry for the draft v0.12: the review and its fixes, the
draft, the CMS reader with its own profile, the addresses of the locator,
the CLI, the new test data, and what is pending.
- capsule/format3.go: the comments of EncodeSecurityWith,
EncodeAuthorSignature and EncodeSeal no longer say that this version
defines no alg and no seal_type.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// EncodeAuthorSignature returns the content of key 2 of security, {0: alg,
// 1: key, 2: signature} (spec §29.3). This version defines alg 1, AlgEd25519,
// and alg 2, AlgCMS, whose key 1 holds SIGNERS: EncryptFiles writes them, and
// only a generator of test vectors writes another alg, such as AlgTest.
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
func EncodeAuthorSignature ( alg uint64 , key , signature [ ] byte ) ( [ ] byte , error ) {
var e codec . Encoder
( & authorSignature { alg , key , signature } ) . encode ( & e )
return e . Out ( )
}
// seal is the content of key 3 of security: {0: seal_type, 1: token}.
type seal struct {
sealType uint64
token [ ] byte
}
func ( s * seal ) encode ( e * codec . Encoder ) {
e . Map ( 2 )
e . Uint ( 0 )
e . Uint ( s . sealType )
e . Uint ( 1 )
e . Bstr ( s . token )
}
func ( s * seal ) decode ( d * codec . Decoder ) error {
return decodeItem ( d , 2 , func ( k uint64 ) ( err error ) {
switch k {
case 0 :
s . sealType , err = decodeAlg ( d )
case 1 :
s . token , err = d . Bstr ( 0 , maxSecurityItem )
default :
err = fmt . Errorf ( "key %d is not defined: %w" , k , datekeys . ErrNonCanonicalCBOR )
}
return err
} )
}
func decodeSeal ( b [ ] byte ) ( * seal , error ) {
var s seal
if err := codec . Unmarshal ( b , s . decode , s . encode ) ; err != nil {
return nil , err
}
return & s , nil
}
Docs at spec v0.11 and the draft v0.12: READMEs, SECURITY, traceability, CHANGELOG
The session that closed v0.11 left the documentation at v0.10 (review of
2 October, G14).
- README.md and README.es.md say the same again: the reference implements
v0.11, tagged, and the branch v0.12 the draft; SpecVersion 0.11; the area
of 32 KiB in the picture of BODY; the table of modules with authorkey,
internal/cms, internal/der, locator, wordkey and the public note; and what
the CLI does now: encrypt -sign shows the key and the code of
AUTHOR_MESSAGE before it signs, decrypt -expect-author writes nothing
unless the key of an F4 matches, the lines of the verdicts break behind a
mark, and decrypt and inspect say when a public note is not shown. The
security properties no longer say that no signature is checked.
- SECURITY.md: the scope is v0.11 and the draft v0.12; the limits of a
signature, a seal and a key of words; the standard library among the
cryptographic dependencies.
- docs/traceability.md at the draft v0.12: rows for 24.1, 29.8 to 29.12,
38.1 and 44.1, and rows 29.2, 29.3, 29.7, 62.1, 64, 67, 70, 72 and 76 up
to date, with the code and the tests of each. The cases of spec 64 that
security_cms.json and locator.json still lack are marked pending.
- CHANGELOG.md: an entry for the draft v0.12: the review and its fixes, the
draft, the CMS reader with its own profile, the addresses of the locator,
the CLI, the new test data, and what is pending.
- capsule/format3.go: the comments of EncodeSecurityWith,
EncodeAuthorSignature and EncodeSeal no longer say that this version
defines no alg and no seal_type.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 days ago
// EncodeSeal returns the content of key 3 of security, {0: seal_type, 1:
// token} (spec §29.3). This version defines seal_type 2, SealTypeRFC3161,
// which EncryptFiles writes; only a generator of test vectors writes another
// seal_type, such as SealTypeTest.
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
func EncodeSeal ( sealType uint64 , token [ ] byte ) ( [ ] byte , error ) {
var e codec . Encoder
( & seal { sealType , token } ) . encode ( & e )
return e . Out ( )
}
// decodeAlg reads alg or seal_type, from 1 to 2^32 - 1.
func decodeAlg ( d * codec . Decoder ) ( uint64 , error ) {
v , err := d . Uint ( maxAlg )
if err == nil && v == 0 {
err = fmt . Errorf ( "0 is not defined: %w" , datekeys . ErrNonCanonicalCBOR )
}
return v , err
}
// decodeItem reads a map of exactly n required keys, 0 to n-1, with field.
func decodeItem ( d * codec . Decoder , n int , field func ( k uint64 ) error ) error {
pairs , err := d . Map ( n )
if err != nil {
return err
}
var seen uint
for range pairs {
k , err := d . Key ( )
if err != nil {
return err
}
if err := field ( k ) ; err != nil {
return fmt . Errorf ( "key %d: %w" , k , err )
}
seen |= 1 << k
}
if err := required ( seen , n ) ; err != nil {
return err
}
return d . EndMap ( )
}
// Head is the head of a format 3 capsule (spec §29.4).
type Head struct {
Salt [ SaltSize ] byte
// Comment and Author are the comment and the declared author, "" when
// absent. The declared author is text of the creator and proves nothing.
Comment , Author string
// Files are the entries, in strictly ascending byte order of their paths.
Files [ ] File
// Critical and Noncritical are the extensions of the head (keys 6 and 7).
Critical , Noncritical [ ] extension . Extension
}
// File is an entry of the head: a file of CONTENT.
type File struct {
Path string
Size , Start , End uint64
SHA256 [ 32 ] byte
// MTime is the modification time of the file at its source, in seconds
// since 1970-01-01 UTC, when HasMTime. It is informative.
MTime uint64
HasMTime bool
}
// headWire is HEAD_CBOR as it is encoded.
type headWire struct {
h * Head
}
func ( w * headWire ) encode ( e * codec . Encoder ) {
h := w . h
n := 3 + nonEmpty ( h . Critical ) + nonEmpty ( h . Noncritical )
if h . Comment != "" {
n ++
}
if h . Author != "" {
n ++
}
if len ( h . Files ) > 0 {
n ++
}
e . Map ( n )
e . Uint ( 0 )
e . Text ( HeadTypeTag )
e . Uint ( 1 )
e . Uint ( HeadVersion )
e . Uint ( 2 )
e . Bstr ( h . Salt [ : ] )
if h . Comment != "" {
e . Uint ( 3 )
e . Text ( h . Comment )
}
if h . Author != "" {
e . Uint ( 4 )
e . Text ( h . Author )
}
if len ( h . Files ) > 0 {
e . Uint ( 5 )
e . Array ( len ( h . Files ) )
for i := range h . Files {
encodeFile ( e , & h . Files [ i ] )
}
}
encodeExtensions ( e , 6 , h . Critical , h . Noncritical )
}
func encodeFile ( e * codec . Encoder , f * File ) {
n := 5
if f . HasMTime {
n ++
}
e . Map ( n )
e . Uint ( 0 )
e . Text ( f . Path )
e . Uint ( 1 )
e . Uint ( f . Size )
e . Uint ( 2 )
e . Uint ( f . Start )
e . Uint ( 3 )
e . Uint ( f . End )
e . Uint ( 4 )
e . Bstr ( f . SHA256 [ : ] )
if f . HasMTime {
e . Uint ( 5 )
e . Uint ( f . MTime )
}
}
// decode reads HEAD_CBOR with the rules of the third layer: the CDDL, R1 and
// R8 (spec §29.4, §29.5). The fourth layer comes after, in DecodeHead.
func ( w * headWire ) decode ( d * codec . Decoder ) error {
h := w . h
pairs , err := d . Map ( 8 )
if err != nil {
return err
}
var seen uint
for range pairs {
k , err := d . Key ( )
if err != nil {
return err
}
switch k {
case 0 :
_ , err = d . Text ( len ( HeadTypeTag ) )
case 1 :
_ , err = d . Uint ( HeadVersion )
case 2 :
var salt [ ] byte
if salt , err = d . Bstr ( SaltSize , SaltSize ) ; err == nil {
copy ( h . Salt [ : ] , salt )
}
case 3 :
h . Comment , err = decodeText ( d , MaxCommentLen , "comment" )
case 4 :
h . Author , err = decodeText ( d , MaxAuthorLen , "declared author" )
case 5 :
h . Files , err = decodeFiles ( d )
case 6 :
h . Critical , err = extension . DecodeArray ( d )
case 7 :
h . Noncritical , err = extension . DecodeArray ( d )
default :
return fmt . Errorf ( "key %d is not defined: %w" , k , datekeys . ErrNonCanonicalCBOR )
}
if err != nil {
return fmt . Errorf ( "key %d: %w" , k , err )
}
seen |= 1 << k
}
if err := required ( seen , 3 ) ; err != nil {
return err
}
return d . EndMap ( )
}
// decodeText reads a text of 1 to max bytes.
func decodeText ( d * codec . Decoder , max int , what string ) ( string , error ) {
s , err := d . Text ( max )
if err == nil && s == "" {
err = fmt . Errorf ( "empty %s: %w" , what , datekeys . ErrNonCanonicalCBOR )
}
return s , err
}
// decodeFiles reads the array of entries: 1 to MaxFiles, each path of 1 to
// MaxPathLen bytes (R1), in strictly ascending byte order (R8).
func decodeFiles ( d * codec . Decoder ) ( [ ] File , error ) {
n , err := d . Array ( MaxFiles )
if err != nil {
return nil , err
}
if n == 0 {
return nil , fmt . Errorf ( "empty array of files: %w" , datekeys . ErrNonCanonicalCBOR )
}
files := make ( [ ] File , 0 , min ( n , 1024 ) )
for i := range n {
var f File
if err := decodeItemOptional ( d , 5 , 6 , func ( k uint64 ) ( err error ) {
switch k {
case 0 :
f . Path , err = d . Text ( MaxPathLen )
if err == nil && f . Path == "" {
err = fmt . Errorf ( "R1: the path is empty: %w" , datekeys . ErrNonCanonicalCBOR )
}
case 1 :
f . Size , err = d . Uint ( MaxPayloadLength )
case 2 :
f . Start , err = d . Uint ( MaxPayloadLength )
case 3 :
f . End , err = d . Uint ( MaxPayloadLength )
case 4 :
var sum [ ] byte
if sum , err = d . Bstr ( 32 , 32 ) ; err == nil {
copy ( f . SHA256 [ : ] , sum )
}
case 5 :
f . MTime , err = d . Uint ( MaxMTime )
f . HasMTime = err == nil
default :
err = fmt . Errorf ( "key %d is not defined: %w" , k , datekeys . ErrNonCanonicalCBOR )
}
return err
} ) ; err != nil {
return nil , fmt . Errorf ( "file %d: %w" , i + 1 , err )
}
if i > 0 && f . Path <= files [ i - 1 ] . Path {
return nil , fmt . Errorf ( "file %d: R8: the path is not after the path of file %d in byte order: %w" , i + 1 , i , datekeys . ErrNonCanonicalCBOR )
}
files = append ( files , f )
}
return files , nil
}
// decodeItemOptional reads a map whose keys 0 to required-1 are required and
// whose keys up to max-1 are optional.
func decodeItemOptional ( d * codec . Decoder , need , max int , field func ( k uint64 ) error ) error {
pairs , err := d . Map ( max )
if err != nil {
return err
}
var seen uint
for range pairs {
k , err := d . Key ( )
if err != nil {
return err
}
if err := field ( k ) ; err != nil {
return fmt . Errorf ( "key %d: %w" , k , err )
}
seen |= 1 << k
}
if err := required ( seen , need ) ; err != nil {
return err
}
return d . EndMap ( )
}
// EncodeHead returns HEAD_CBOR for h. The files must already be in byte
// order of their paths. The writer checks the result with DecodeHead, the
// rules of the reader (spec §62.1 rule 17).
func EncodeHead ( h * Head ) ( [ ] byte , error ) {
w := headWire { h : & Head { Salt : h . Salt , Comment : h . Comment , Author : h . Author , Files : h . Files } }
var err error
if w . h . Critical , err = extension . Canonical ( h . Critical ) ; err != nil {
return nil , err
}
if w . h . Noncritical , err = extension . Canonical ( h . Noncritical ) ; err != nil {
return nil , err
}
if err := extension . CheckDisjoint ( w . h . Critical , w . h . Noncritical ) ; err != nil {
return nil , err
}
if len ( h . Files ) > MaxFiles {
return nil , fmt . Errorf ( "capsule: head: %d files, more than %d" , len ( h . Files ) , MaxFiles )
}
var e codec . Encoder
w . encode ( & e )
return e . Out ( )
}
// DecodeHead validates and decodes HEAD_CBOR with the layers of spec §69.1
// (spec §29.4, §63 step 17.4): the type tag and the version (layer 2), the
// CDDL with R1 and R8 (layer 3), and then, in key order, the comment and the
// declared author (§29.6), the files with R2 to R6c, R10 and their layout,
// R7 and R9 over the tree (§29.5), all ErrHeadInvalid, and the critical
// extensions with reg (layer 4).
func DecodeHead ( b [ ] byte , reg extension . Registry ) ( * Head , error ) {
Format 3, step 4: the writer
EncryptFiles writes format 3 (spec 29.2 to 29.6, 61, 62, 62.1): the
files of a list of Sources, each read twice, with the comment and the
declared author.
- Before anything is written: the paths and the texts are checked with
the rules of the reader, in the words of a writer, naming the rule
and the character, and the two paths of an R7 collision (rule 15);
the comment has its CR LF and lone CR turned into LF (29.6); L is
measured with a head whose salt and SHA-256 are zero, as long as the
final one, and the first reading hashes each file, which must have
exactly its Size.
- The files go in the byte order of their paths (R8), whatever the
order of the Sources; the mtime is kept only from 1970 to 9999,
never clipped (rule 16); at least one file or a comment (rule 14).
- The head, with a fresh salt, the control and the security area are
decoded with the rules of the reader before sealing (rule 17), and
the frame is checked against L. The area is 512 bytes with the
empty security, whatever the options (rule 13).
- The second reading writes each file into PAYLOAD_AGE and fails if its
size or SHA-256 changed (rule 18).
- Encrypt and EncryptFiles share the sealing; Encrypt writes format 2
only with the new TestVectors option (rule 1), and takes no head.
The test data generators set it, and so does the CLI until step 5
moves it to EncryptFiles.
- Result.Head is the head written. DecodeHead keeps the check of the
critical extensions apart, so that the self-check decodes the head
as the one of the control does.
- The examples and the live test write with EncryptFiles.
- The reader tests had a literal U+202E, now escaped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
h , err := decodeHead ( b )
if err != nil {
return nil , err
}
if err := extension . CheckCriticalIn ( extension . Head , h . Critical , reg ) ; err != nil {
return nil , fmt . Errorf ( "capsule: head: %w" , err )
}
return h , nil
}
// decodeHead is DecodeHead but for the critical extensions, whose knowledge
// depends on the reader: the self-check of a writer decodes with it, as it
// decodes the control with DecodeControl (spec §62.1 rule 17).
func decodeHead ( b [ ] byte ) ( * Head , error ) {
Format 3, step 2: the codec of BODY, security and the head
- Format3 and the control of schema version 3, with the keys of
version 2 (spec 31). The PRELUDE still rejects VERSION 3 until the
reader opens format 3, in step 3, with the test data that expect it.
- The frame of BODY (spec 29.2): AREA_LEN, SECURITY_LEN and HEAD_LEN,
their limits against L and the zeros of the area, all ERR_INTEGRITY.
- security (spec 29.3, 29.7): the outer map, with the signature and
the seal as separately encoded byte strings, and its verdicts X, F0,
F1, S0, S1 and S2, which never fail. The first row that holds
decides, so a seal that breaks its schema is S2 before its type is
read. Writers of this version write it empty, 22 bytes.
- The head (spec 29.4): layer 2 with its type tag and version 1;
layer 3 with the CDDL, R1 and R8; layer 4 in key order, the comment
and the declared author, each file with R2 to R6c, R10 and its
layout, R7 and R9 over the tree, all ERR_HEAD_INVALID, and then the
critical extensions of the new extension.Head object.
- ERR_HEAD_INVALID is declared; All lists it once SpecVersion moves to
0.10 with the test data, in step 6.
- The control tests take format 4 as the caller error that format 3
was, as section 76 of the spec anticipated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
if len ( b ) > MaxHeadLen {
return nil , fmt . Errorf ( "capsule: head: %d bytes, more than %d: %w" , len ( b ) , MaxHeadLen , datekeys . ErrIntegrity )
}
if err := codec . CheckSchema ( b , HeadTypeTag , HeadVersion ) ; err != nil {
return nil , fmt . Errorf ( "capsule: head: %w" , err )
}
h := & Head { }
w := headWire { h : h }
if err := codec . Unmarshal ( b , w . decode , w . encode ) ; err != nil {
return nil , fmt . Errorf ( "capsule: head: %w" , err )
}
if err := extension . CheckDisjoint ( h . Critical , h . Noncritical ) ; err != nil {
return nil , fmt . Errorf ( "capsule: head: %w" , err )
}
if err := checkHeadFields ( h ) ; err != nil {
return nil , err
}
return h , nil
}
// checkHeadFields applies the rules of the fourth layer with a code of their
// own, ErrHeadInvalid: keys 3, 4 and 5, in that order.
func checkHeadFields ( h * Head ) error {
invalid := func ( what string , err error ) error {
return fmt . Errorf ( "capsule: head: %s%v: %w" , what , err , datekeys . ErrHeadInvalid )
}
if h . Comment != "" {
if err := pathrule . CheckComment ( h . Comment ) ; err != nil {
return invalid ( "comment: " , err )
}
}
if h . Author != "" {
if err := pathrule . CheckAuthor ( h . Author ) ; err != nil {
return invalid ( "declared author: " , err )
}
}
var end uint64
paths := make ( [ ] string , len ( h . Files ) )
for i := range h . Files {
f := & h . Files [ i ]
if err := pathrule . CheckPath ( f . Path ) ; err != nil {
return invalid ( fmt . Sprintf ( "file %d: " , i + 1 ) , err )
}
switch {
case f . Start != end :
return invalid ( fmt . Sprintf ( "file %d: " , i + 1 ) , fmt . Errorf ( "start %d is not %d, the end of the file before" , f . Start , end ) )
case f . End < f . Start || f . End - f . Start != f . Size :
return invalid ( fmt . Sprintf ( "file %d: " , i + 1 ) , fmt . Errorf ( "from start %d to end %d is not the size %d" , f . Start , f . End , f . Size ) )
}
end = f . End
paths [ i ] = f . Path
}
if err := pathrule . CheckTree ( paths ) ; err != nil {
return invalid ( "" , err )
}
return nil
}
// CheckHeadEnd checks that the files fill CONTENT, of c bytes: the last one
// ends at C, or C is 0 without files (spec §29.4, §63 step 17.5).
// ErrIntegrity if not.
func CheckHeadEnd ( h * Head , c uint64 ) error {
var end uint64
if n := len ( h . Files ) ; n > 0 {
end = h . Files [ n - 1 ] . End
}
if end != c {
return fmt . Errorf ( "capsule: BODY: the files end at byte %d of a content of %d bytes: %w" , end , c , datekeys . ErrIntegrity )
}
return nil
}