-----BEGIN PGP SIGNATURE-----
-iHUEABYKAB0WIQTbL/jtRAp+lJhvt3bSI36ECQhstwUCaGEDswAKCRDSI36ECQhs
-twPcAPwLJuuTjhU3y6sSRNqr/69Q452vv1a2TWUNxTCyxCPd0wD/fWPvM/PxO8aW
-lt/Yfko5vPVbnwFP/GczCzugHFGWZws=
-=ydWw
+iJEEABYKADkWIQTbL/jtRAp+lJhvt3bSI36ECQhstwUCaNf4oBsUgAAAAAAEAA5t
+YW51MiwyLjUrMS4xMSwyLDMACgkQ0iN+hAkIbLcCQAEAzsCbtqjkxqxtKWuK5qYb
+dDgrkPU2J7c4nq8OVnvLfXoBANcnFYroJtAKt3xQYO9I3My8vLBH68pkFHFj9WTR
+sPIO
+=HAQ6
-----END PGP SIGNATURE-----
(*failReason) = "schema failed";
return KEKSErrUnsatisfiedSchema;
}
- size_t idx = KEKSItemsGetByKey(items, KEKSItemsGetByKey(items, 0, "load"), "v");
+ size_t idx = KEKSItemsGetByKey(items, 0, "data");
cer->pub = KEKSItemsGetByKey(items, idx, "pub");
cer->pub = items->list[cer->pub].atom.v.list.head;
cer->sub = KEKSItemsGetByKey(items, idx, "sub");
return KEKSErrNo;
}
if (items->list[idx].atom.v.list.len != 1) {
- (*failReason) = "len(/load/sigs) != 1";
+ (*failReason) = "len(/sigs) != 1";
return KEKSErrUnsatisfiedSchema;
}
cer->sig = items->list[idx].atom.v.list.head;
size_t off = 0;
if (!KEKSItemsEncode(
&(cer->items),
- KEKSItemsGetByKey(&(cer->items), 0, "load"),
+ KEKSItemsGetByKey(&(cer->items), 0, "data"),
&off,
buf,
cap)) {
- (*failReason) = "can not prepare tbs: load";
+ (*failReason) = "can not prepare tbs: data";
return false;
}
- size_t off2 = 0;
- if (!KEKSItemsEncode(
- &(cer->items),
- KEKSItemsGetByKey(&(cer->items), cer->sig, "tbs"),
- &off2,
- buf + off,
- cap - off)) {
- (*failReason) = "can not prepare tbs: tbs";
- return false;
+ {
+ size_t off2 = 0;
+ if (!KEKSItemsEncode(
+ &(cer->items),
+ KEKSItemsGetByKey(&(cer->items), 0, "tbs"),
+ &off2,
+ buf + off,
+ cap - off)) {
+ (*failReason) = "can not prepare tbs: tbs";
+ return false;
+ }
+ off += off2;
+ off2 = 0;
+ if (!KEKSItemsEncode(
+ &(cer->items),
+ KEKSItemsGetByKey(&(cer->items), cer->sig, "tbs"),
+ &off2,
+ buf + off,
+ cap - off)) {
+ (*failReason) = "can not prepare tbs: sig-tbs";
+ return false;
+ }
+ off += off2;
}
- off += off2;
for (size_t i = 0; opts.sigVerifiers[i].algo != NULL; i++) {
if (!KEKSStrEqual(&(pubA->atom), opts.sigVerifiers[i].algo)) {
// @item .items
// Holds parsed @ref{KEKSItems} items.
// @item .pub
-// Items index of the first @code{/load/v/pub}, certificate's public key.
+// Items index of the first @code{/data/pub}, certificate's public key.
// @item .sub
-// Items index of the @code{/load/v/sub}, certificate's subject.
+// Items index of the @code{/data/sub}, certificate's subject.
// @item .sig
// Items index of the first @code{/sigs}, certificate's signature.
// @item .cid
if err != nil {
log.Fatalln("public key:", len(pubs), ":", err)
}
- load := signed.PubLoad()
- if !load.Can(sign.KUKEM) {
+ pubData := signed.PubData()
+ if !pubData.Can(sign.KUKEM) {
log.Println(
"public key:", len(pubs), ": does not have",
sign.KUKEM, "key usage",
)
}
- if len(load.Pub) != 1 {
+ if len(pubData.Pub) != 1 {
log.Fatalln("public key:", len(pubs), ": expected single public key")
}
- pubs = append(pubs, load.Pub[0])
- pubIds = append(pubIds, load.Id)
+ pubs = append(pubs, pubData.Pub[0])
+ pubIds = append(pubIds, pubData.Id)
}
}
fdPubR.Close()
}
var prvRaw []byte
- var pubLoad map[string]any
+ var pubData map[string]any
if doCertify {
- pubLoad = (*signed.Load.V).(map[string]any)
+ pubData = (*signed.Data).(map[string]any)
} else {
var pub []byte
switch *algo {
}
}
{
- pubLoad = map[string]any{
+ pubData = map[string]any{
"sub": sub,
"pub": []cm.AV{{A: *algo, V: pub}},
}
default:
log.Fatal("unsupported algorithm")
}
- _, err = keks.Encode(hasher, pubLoad["pub"], nil)
+ _, err = keks.Encode(hasher, pubData["pub"], nil)
if err != nil {
log.Fatal(err)
}
- pubLoad["id"] = hasher.Sum(nil)
+ pubData["id"] = hasher.Sum(nil)
if err != nil {
log.Fatal(err)
}
}
if len(ku) > 0 {
- pubLoad["ku"] = ku
+ pubData["ku"] = ku
}
}
{
- pubLoadAny := any(pubLoad)
- signed = &sign.Signed{Load: sign.Load{T: "pub", V: &pubLoadAny}}
+ pubLoadAny := any(pubData)
+ signed = &sign.Signed{TBS: sign.SDTBS{T: "pub"}, Data: &pubLoadAny}
}
if doCertify {
if err = signed.CertifyWith(
- caPubs[0].PubLoad(), caPrv, since, till,
+ caPubs[0].PubData(), caPrv, since, till,
); err != nil {
log.Fatal(err)
}
fdPubR := os.NewFile(FdPubR, "pub-in")
fdPrvR := os.NewFile(FdPrvR, "prv-in")
- var pubs []*sign.PubLoad
+ var pubs []*sign.PubData
var err error
{
data := mustReadAll(fdPubR)
if err != nil {
log.Fatal(err)
}
- pubs = append(pubs, signed.PubLoad())
+ pubs = append(pubs, signed.PubData())
}
fdPubR.Close()
}
if err != nil {
log.Fatal(err)
}
- if signed.Load.T != *typ {
- log.Fatalln("differing load type:", signed.Load.T)
+ if signed.TBS.T != *typ {
+ log.Fatalln("differing load type:", signed.TBS.T)
}
for _, sig := range signed.Sigs {
sid := sig.TBS["sid"].([]byte)
continue
}
signerFound = true
- var tbs *sign.TBS
- tbs, err = sig.TBSGet()
+ var sigTBS *sign.SigTBS
+ sigTBS, err = sig.TBSGet()
if err != nil {
log.Fatal(err)
}
if len(encryptedTo) > 0 {
- if len(tbs.EncryptedTo) == 0 {
+ if len(sigTBS.EncryptedTo) == 0 {
log.Fatalln(hex.EncodeToString(sid), "missing encrypted-to")
}
found := false
- for _, their := range tbs.EncryptedTo {
+ for _, their := range sigTBS.EncryptedTo {
for _, our := range encryptedTo {
if bytes.Equal(our, their) {
found = true
}
}
var signed sign.Signed
- signed.Load.T = *typ
+ signed.TBS.T = *typ
tbs := make(map[string]any)
if !*noWhen {
tbs["when"] = time.Now().UTC().Truncate(time.Millisecond)
ErrBadSigAlgo = errors.New("bad signature algo")
)
-// Public key load.
-type PubLoad struct {
+// Public key' contents.
+type PubData struct {
KU map[string]*struct{} `keks:"ku"`
Sub map[string]string `keks:"sub"`
Crit []map[string]any `keks:"crit"`
Id []byte `keks:"id"`
}
-// Parse KEKS-encoded data as Signed with the PubLoad (certificate) contents.
+// Parse KEKS-encoded data as Signed with the PubData (certificate) contents.
func PubParse(data []byte) (signed *Signed, tail []byte, err error) {
{
var magic keks.Magic
}
tail = d.B
signed = &sd
- if sd.Load.T != "pub" {
+ if sd.TBS.T != "pub" {
err = errors.New("PubParse: wrong load type")
}
return
}
// Check if public key has desired ku capability.
-func (pub *PubLoad) Can(ku string) (yes bool) {
+func (pub *PubData) Can(ku string) (yes bool) {
_, yes = pub.KU[ku]
return
}
-// Sign the provided Signed, having PubLoad payload with the provided
-// parent's PubLoad and prv key. Certification CID will be automatically
+// Sign the provided Signed, having PubData payload with the provided
+// parent's PubData and prv key. Certification CID will be automatically
// generated UUIDv7. since and till times must not have nanoseconds part.
func (signed *Signed) CertifyWith(
- parent *PubLoad,
+ parent *PubData,
prv Iface,
since, till time.Time,
) error {
// Verify signature of signed data. ErrSigInvalid will be returned in
// case of invalid signature.
-func (pub *PubLoad) CheckSignature(algo string, signed, signature []byte) (err error) {
+func (pub *PubData) CheckSignature(algo string, signed, signature []byte) (err error) {
if !pub.Can(KUSig) || len(pub.Pub) != 1 {
err = errors.New("pub can not sign")
return
// Verify signature of signed data, by providing prehashed data.
// ErrSigInvalid will be returned in case of invalid signature.
-func (pub *PubLoad) CheckSignaturePrehash(
+func (pub *PubData) CheckSignaturePrehash(
algo string,
prehash, signature []byte,
) (err error) {
return
}
-// Verify Signed PubLoad certification signature with provided parent.
+// Verify Signed PubData certification signature with provided parent.
// If prehasher is specified, then prehashed signature mode is used.
// Currently only single signature can be verified.
func (signed *Signed) CertificationCheckSignatureFrom(
- parent *PubLoad,
+ parent *PubData,
prehasher *hash.Hash,
) (err error) {
if !parent.Can(KUSig) || len(parent.Pub) != 1 {
}
if prehasher == nil {
var tbs bytes.Buffer
- if _, err = keks.Encode(&tbs, signed.Load, nil); err != nil {
+ if _, err = keks.Encode(&tbs, signed.Data, nil); err != nil {
+ return
+ }
+ if _, err = keks.Encode(&tbs, signed.TBS, nil); err != nil {
return
}
if _, err = keks.Encode(&tbs, sig.TBS, nil); err != nil {
}
return parent.CheckSignature(sig.Sign.A, tbs.Bytes(), sig.Sign.V)
} else {
- if _, err = keks.Encode(*prehasher, signed.Load, nil); err != nil {
+ if _, err = keks.Encode(*prehasher, signed.Data, nil); err != nil {
+ return
+ }
+ if _, err = keks.Encode(*prehasher, signed.TBS, nil); err != nil {
return
}
if _, err = keks.Encode(*prehasher, sig.TBS, nil); err != nil {
return errors.New("can not find necessary sid")
}
-// Get PubLoad from Signed.
+// Get PubData from Signed.
// Returns nil if Signed does not hold it (or it is not yet parsed).
-func (signed *Signed) PubLoad() *PubLoad {
- if signed.Load.T != "pub" || signed.Load.V == nil {
+func (signed *Signed) PubData() *PubData {
+ if signed.TBS.T != "pub" || signed.Data == nil {
return nil
}
- v, ok := (*signed.Load.V).(map[string]any)
+ v, ok := (*signed.Data).(map[string]any)
if !ok {
return nil
}
- var pubLoad PubLoad
- err := keks.Map2Struct(&pubLoad, v)
+ var pubData PubData
+ err := keks.Map2Struct(&pubData, v)
if err != nil {
return nil
}
- return &pubLoad
+ return &pubData
}
-// Verify signed Signed PubLoad certification against pubs chain of
+// Verify signed Signed PubData certification against pubs chain of
// public keys at specified point of time t.
func (signed *Signed) CertificationVerify(pubs []*Signed, t time.Time) (err error) {
if len(signed.Sigs) == 0 {
return errors.New("no sigs")
}
- var tbs *TBS
- tbs, err = signed.Sigs[0].TBSGet()
+ var sigTBS *SigTBS
+ sigTBS, err = signed.Sigs[0].TBSGet()
if err != nil {
return
}
{
- exp := tbs.Exp
+ exp := sigTBS.Exp
if t.Before(exp[0]) || t.Equal(exp[0]) {
err = errors.New("pub is not active")
return
return
}
}
- sid := tbs.SID
- if bytes.Equal(sid, signed.PubLoad().Id) {
- return signed.CertificationCheckSignatureFrom(signed.PubLoad(), nil)
+ sid := sigTBS.SID
+ if bytes.Equal(sid, signed.PubData().Id) {
+ return signed.CertificationCheckSignatureFrom(signed.PubData(), nil)
}
type FPR [FPRLen]byte
idToPub := make(map[FPR]*Signed, len(pubs))
for _, cer := range pubs {
- pubLoad := cer.PubLoad()
- if !pubLoad.Can(KUSig) || len(pubLoad.Pub) != 1 {
+ pubData := cer.PubData()
+ if !pubData.Can(KUSig) || len(pubData.Pub) != 1 {
err = errors.New("pub can not sign")
return
}
- idToPub[FPR(pubLoad.Id)] = cer
+ idToPub[FPR(pubData.Id)] = cer
}
signer := idToPub[FPR(sid)]
if signer == nil {
- err = fmt.Errorf("no pub found for sid: %v", tbs.SID)
+ err = fmt.Errorf("no pub found for sid: %v", sigTBS.SID)
return
}
- err = signed.CertificationCheckSignatureFrom(signer.PubLoad(), nil)
+ err = signed.CertificationCheckSignatureFrom(signer.PubData(), nil)
if err != nil {
return
}
const SignedMagic = keks.Magic("cm/signed")
-type Load struct {
- V *any `keks:"v,omitempty"`
+type SDTBS struct {
T string `keks:"t"`
}
-type TBS struct {
+type SigTBS struct {
EncryptedTo [][]byte `keks:"encrypted-to"`
Exp []time.Time `keks:"exp"`
SID []byte `keks:"sid"`
CID uuid.UUID `keks:"cid"`
}
-func (sig *Sig) TBSGet() (*TBS, error) {
- var tbs TBS
+func (sig *Sig) TBSGet() (*SigTBS, error) {
+ var tbs SigTBS
return &tbs, keks.Map2Struct(&tbs, sig.TBS)
}
}
type Signed struct {
- Load Load `keks:"load"`
+ TBS SDTBS `keks:"tbs"`
+ Data *any `keks:"data,omitempty"`
Pubs *[]*Signed `keks:"pubs,omitempty"`
Sigs []*Sig `keks:"sigs,omitempty"`
}
return
}
-// Sign Signed's contents and tbs corresponding data with the
+// Sign Signed's contents and sig-tbs corresponding data with the
// provided prv signer, having parent certififer. Signature is
// appended to the signed.Sigs. parent must have "sig" key-usage.
func (signed *Signed) SignWith(
- parent *PubLoad,
+ parent *PubData,
prv Iface,
- tbs map[string]any,
+ sigTBS map[string]any,
) (err error) {
if !parent.Can(KUSig) || len(parent.Pub) != 1 {
return errors.New("parent can not sign")
}
- tbs["sid"] = parent.Id
+ sigTBS["sid"] = parent.Id
var tbsRaw []byte
if prv.Mode() == mode.Pure {
var b bytes.Buffer
- if _, err = keks.Encode(&b, signed.Load, nil); err != nil {
+ if _, err = keks.Encode(&b, signed.Data, nil); err != nil {
return
}
- if _, err = keks.Encode(&b, tbs, nil); err != nil {
+ if _, err = keks.Encode(&b, signed.TBS, nil); err != nil {
+ return
+ }
+ if _, err = keks.Encode(&b, sigTBS, nil); err != nil {
return
}
tbsRaw = b.Bytes()
} else {
- if _, err = keks.Encode(*prv.Prehasher(), signed.Load, nil); err != nil {
+ if _, err = keks.Encode(*prv.Prehasher(), signed.Data, nil); err != nil {
+ return
+ }
+ if _, err = keks.Encode(*prv.Prehasher(), signed.TBS, nil); err != nil {
return
}
- if _, err = keks.Encode(*prv.Prehasher(), tbs, nil); err != nil {
+ if _, err = keks.Encode(*prv.Prehasher(), sigTBS, nil); err != nil {
return
}
tbsRaw = (*prv.Prehasher()).Sum(nil)
}
- sig := Sig{TBS: tbs}
+ sig := Sig{TBS: sigTBS}
sig.Sign.A = prv.Algo()
sig.Sign.V, err = prv.Sign(rand.Reader, tbsRaw, crypto.Hash(0))
if err != nil {
Public-key based [cm/kem/]s provides sender authentication
*only* if "/kem/*/from" field is specified. It should contain public
-key's "/load/v/id", but may be equal to 256-bit zeros, to explicitly
+key's "/data/id", but may be equal to 256-bit zeros, to explicitly
specify that sender's public key is used, but it is anonymous and
hidden. It is not specified how recipient should find corresponding
sender's key that way -- implementation/protocol specific.
KEM combiner nearly fully resembles:
=> https://datatracker.ietf.org/doc/draft-josefsson-chempat/ Chempat\r
-If sender/recipient's public key structure contains
-"/load/v/prehash" field, then it could be used as already
-calculated values of SHAKE256 calls of PRK.
+If sender/recipient's public key structure contains "/data/prehash" field,
+then it could be used as already calculated values of SHAKE256 calls of PRK.
Public key is the [cm/signed/] structure.
Stored in a file, it should begin with "cm/pub" [encoding/MAGIC].
-Its "/load/t" equals to "pub". "/load/v" contains "cm/pub/load":
+Its "/tbs/t" equals to "pub". "/data" contains:
-<< [schemas/pub-load.tcl]\r
+<< [schemas/pub-data.tcl]\r
sub:
Subject is a map of arbitrary strings. Currently no constraints on
above. It *must* be absent if empty.
crit:
Optional critical (in terms of X.509) extensions. Non-critical
- ones may be placed outside that map, directly in cm/pub/load.
+ ones may be placed outside that map, directly in /data.
It *must* be absent if empty. Values are extension specific.
[cm/signed/]'s "tbs" *must* contain additional fields:
MAGIC cm/pub
MAP {
- load {MAP {
+ tbs {MAP {
t {STR pub}
- v {MAP {
- id {BIN "6aee..."}
- pub {LIST {
- {MAP {
- a {STR ed25519-blake2b}
- v {BIN "c1bf..."}
- }}
- }}
- sub {MAP {
- N {STR test}
+ }}
+ data {MAP {
+ id {BIN "6aee..."}
+ pub {LIST {
+ {MAP {
+ a {STR ed25519-blake2b}
+ v {BIN "c1bf..."}
}}
}}
+ sub {MAP {
+ N {STR test}
+ }}
}}
sigs {LIST {
{MAP {
Public key's fingerprint should be calculated using SHAKE128.
=> https://keccak.team/ SHAKE XOF function\r
-Optional "/load/v/prehash" field can contain the SHAKE256 hash
-of the concatenated public keys in "/load/v/pub/0", that could
+Optional "/data/prehash" field can contain the SHAKE256 hash
+of the concatenated public keys in "/data/pub/0", that could
save resources during [cm/kem/mceliece6960119-x25519-hkdf-shake256]
KDF calculations.
Signature is created by signing the:
- [detached-data] || /load || /sig/./tbs
+ data || /tbs || /sig/./tbs
-If no "/load/v" is provided, then the data is detached from the
+If no "/data" is provided, then the data is detached from the
"cm/signed" structure itself and is fed into hasher before that
structure. You can provide it any way you wish, but for keeping
that detached data closely to the "cm/signed", you should use the
following approach:
- prehash || BLOB(detached-data) || cm/signed
+ prehash || BLOB(data) || cm/signed
<< [schemas/prehash.tcl]\r
<< [schemas/pub.tcl]\r
<< [schemas/fpr.tcl]\r
-<< [schemas/pub-load.tcl]\r
+<< [schemas/pub-data.tcl]\r
<< [schemas/pub-sig-tbs.tcl]\r
schema.tcl calls "schemas {s0 cmds0 s1 cmds1 ...}" command to produce
-pub-load {
+pub-data {
{field . {map}}
{field id {with fpr}}
{field crit {} !exists}
pub {
{field . {map}}
- {field load {with load}}
- {field sigs {list} {of sig} >0 optional}
+ {field tbs {with tbs}}
+ {field data {with pub-data}}
{field pubs {list} {of pub} >0 optional}
+ {field sigs {list} {of sig} >0 optional}
}
-load {
+tbs {
{field . {map}}
{field t {str} =pub}
- {field v {with pub-load}}
}
av {
}
schema-include fpr.tcl
-schema-include pub-load.tcl
+schema-include pub-data.tcl
schema-include pub-sig-tbs.tcl
signed {
{field . {map}}
- {field load {with load}}
- {field sigs {list} {of sig} >0 optional}
+ {field tbs {with tbs}}
+ {# field data is optional, arbitrary type}
{field pubs {list} {of type map} >0 optional}
+ {field sigs {list} {of sig} >0 optional}
}
-load {
+tbs {
{field . {map}}
- {field t {str} >0}
- {# field v is optional, arbitrary type}
+ {field t {str} >0} {# type of the data we sign}
}
sig {
{field . {map}}
- {field tbs {with tbs}}
+ {field tbs {with sig-tbs}}
{field sign {with av}}
}
-tbs {
+sig-tbs {
{field . {map}}
{field sid {with fpr}}
{field nonce {bin} >0 optional} {# random bytes}