log.Fatalln("public key:", len(pubs), ":", err)
}
load := signed.PubLoad()
- if load.KU == nil {
- log.Println("public key:", len(pubs), ": does not have key usages")
- } else {
- if _, ok := (*load.KU)[sign.KUKEM]; !ok {
- log.Println(
- "public key:", len(pubs), ": does not have",
- sign.KUKEM, "key usage",
- )
- }
+ if !load.Can(sign.KUKEM) {
+ log.Println(
+ "public key:", len(pubs), ": does not have",
+ sign.KUKEM, "key usage",
+ )
}
if len(load.Pub) != 1 {
log.Fatalln("public key:", len(pubs), ": expected single public key")
--- /dev/null
+#!/bin/sh
+
+test_description="Check multiple recipients"
+. $SHARNESS_TEST_SRCDIR/sharness.sh
+
+TMPDIR=${TMPDIR:-/tmp}
+
+dd if=/dev/urandom of=$TMPDIR/enc.data bs=300K count=1 2>/dev/null
+
+test_expect_success "0: pub generation" "cmkeytool \
+ -algo sntrup4591761-x25519 -ku kem -sub N=0 \
+ 5>$TMPDIR/enc.0.pub 9>$TMPDIR/enc.0.prv"
+test_expect_success "1: pub generation" "cmkeytool \
+ -algo sntrup4591761-x25519 -ku kem -sub N=1 \
+ 5>$TMPDIR/enc.1.pub 9>$TMPDIR/enc.1.prv"
+
+test_expect_success "encrypting" "
+ cat $TMPDIR/enc.0.pub $TMPDIR/enc.1.pub |
+ cmenctool 4<&0 <$TMPDIR/enc.data >$TMPDIR/enc.enc"
+
+test_expect_success "0: decrypting" "
+ cmenctool -d 8<$TMPDIR/enc.0.prv <$TMPDIR/enc.enc >$TMPDIR/enc.data.got"
+test_expect_success "0: comparing" \
+ "test_cmp $TMPDIR/enc.data $TMPDIR/enc.data.got"
+
+test_expect_success "1: decrypting" "
+ cmenctool -d 8<$TMPDIR/enc.1.prv <$TMPDIR/enc.enc >$TMPDIR/enc.data.got"
+test_expect_success "1: comparing" \
+ "test_cmp $TMPDIR/enc.data $TMPDIR/enc.data.got"
+
+test_done
}
var prvRaw []byte
- var pubLoad *sign.PubLoad
+ var pubLoad map[string]any
if doCertify {
- pubLoad = signed.PubLoad()
+ pubLoad = (*signed.Load.V).(map[string]any)
} else {
var pub []byte
switch *algo {
}
}
{
- pubLoad = &sign.PubLoad{Sub: sub, Pub: []cm.AV{{A: *algo, V: pub}}}
+ pubLoad = map[string]any{
+ "sub": sub,
+ "pub": []cm.AV{{A: *algo, V: pub}},
+ }
var hasher hash.Hash
switch *algo {
case ed25519blake2b.Ed25519BLAKE2b, sntrup4591761x25519.SNTRUP4591761X25519:
default:
log.Fatal("unsupported algorithm")
}
- _, err = keks.Encode(hasher, pubLoad.Pub, nil)
+ _, err = keks.Encode(hasher, pubLoad["pub"], nil)
if err != nil {
log.Fatal(err)
}
- pubLoad.Id = hasher.Sum(nil)
+ pubLoad["id"] = hasher.Sum(nil)
if err != nil {
log.Fatal(err)
}
}
if len(ku) > 0 {
- pubLoad.KU = &ku
+ pubLoad["ku"] = ku
}
}
{
pubLoadAny := any(pubLoad)
- signed = &sign.Signed{Load: sign.SignedLoad{T: "pub", V: &pubLoadAny}}
+ signed = &sign.Signed{Load: sign.Load{T: "pub", V: &pubLoadAny}}
}
if doCertify {
algo=${keyalgo}${merkle}
test_expect_success "$algo: signing" "cmsigtool $merkle \
- -type $typ $encTo \
+ -t $typ $encTo \
4<$TMPDIR/sign.$keyalgo.pub 8<$TMPDIR/sign.$keyalgo.prv \
<$TMPDIR/sign.$keyalgo.data >$TMPDIR/sign.$algo.sig"
test_expect_success "$algo: verifying" "cmsigtool \
- -verify -type $typ 4<$TMPDIR/sign.$keyalgo.pub \
+ -v -t $typ 4<$TMPDIR/sign.$keyalgo.pub \
<$TMPDIR/sign.$algo.sig >$TMPDIR/sign.data.got"
test_expect_success "$algo: comparing" \
"test_cmp $TMPDIR/sign.$keyalgo.data $TMPDIR/sign.data.got"
test_expect_success "$algo: differing type" "! cmsigtool \
- -verify 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null"
+ -v 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null"
test_expect_success "$algo: good encTo" "! cmsigtool \
- -verify $encTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null"
+ -v $encTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null"
test_expect_success "$algo: bad encTo" "! cmsigtool \
- -verify $badEncTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null"
+ -v $badEncTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null"
-test_expect_success "$algo: detached signing" "cmsigtool -detached $merkle \
- -type $typ 4<$TMPDIR/sign.$keyalgo.pub 8<$TMPDIR/sign.$keyalgo.prv \
+test_expect_success "$algo: detached signing" "cmsigtool -d $merkle \
+ -t $typ 4<$TMPDIR/sign.$keyalgo.pub 8<$TMPDIR/sign.$keyalgo.prv \
<$TMPDIR/sign.$keyalgo.data >$TMPDIR/sign.$algo.detached.sig"
test_expect_success "$algo: detached verifying" \
"cat $TMPDIR/sign.$algo.detached.sig $TMPDIR/sign.$keyalgo.data |
- cmsigtool -detached -verify -type $typ 4<$TMPDIR/sign.$keyalgo.pub"
-test_expect_success "$algo: differing type" "! cmsigtool -detached \
- -verify 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null"
-test_expect_success "$algo: good encTo" "! cmsigtool -detached \
- -verify $encTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null"
-test_expect_success "$algo: bad encTo" "! cmsigtool -detached \
- -verify $badEncTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null"
+ cmsigtool -d -v -t $typ 4<$TMPDIR/sign.$keyalgo.pub"
+test_expect_success "$algo: differing type" "! cmsigtool -d \
+ -v 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null"
+test_expect_success "$algo: good encTo" "! cmsigtool -d \
+ -v $encTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null"
+test_expect_success "$algo: bad encTo" "! cmsigtool -d \
+ -v $badEncTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null"
done
func main() {
log.SetFlags(log.Lshortfile)
flag.Usage = usage
- typ := flag.String("type", "data", "Set/check the load type")
- verify := flag.Bool("verify", false, "Do verification")
+ typ := flag.String("t", "data", "Set/check the load type")
+ verify := flag.Bool("v", false, "Do verification")
var encryptedTo [][]byte
flag.Func("encrypted-to", "Set/check encrypted-to, hex", func(v string) error {
to, err := hex.DecodeString(v)
encryptedTo = append(encryptedTo, to)
return nil
})
- detached := flag.Bool("detached", false, "Detached data mode")
+ detached := flag.Bool("d", false, "Detached data mode")
noWhen := flag.Bool("no-when", false, `Do not include "when"`)
doMerkle := flag.Bool("merkle", false, "Use Merkle-tree based hasher")
flag.Parse()
if _, err = decoder.Parse(); err != nil {
log.Fatal(err)
}
- var prehash sign.SignedPrehash
+ var prehash sign.Prehash
var signed sign.Signed
err = decoder.UnmarshalStruct(&prehash)
var hasher hash.Hash
if len(signed.Sigs) > 1 {
log.Fatal("prehash: currently only single signature support")
}
- sig := signed.Sigs[0]
signer := pub.PubLoad()
if signed.Load.T != *typ {
log.Fatalln("differing load type:", signed.Load.T)
}
+ sig := signed.Sigs[0]
+ var tbs *sign.TBS
+ tbs, err = sig.TBSGet()
+ if err != nil {
+ log.Fatal(err)
+ }
if len(encryptedTo) > 0 {
- if sig.TBS.EncryptedTo == nil {
+ if len(tbs.EncryptedTo) == 0 {
log.Fatal("missing encrypted-to")
}
found := false
- for _, their := range sig.TBS.EncryptedTo {
+ for _, their := range tbs.EncryptedTo {
for _, our := range encryptedTo {
if bytes.Equal(our, their) {
found = true
log.Fatal(err)
}
} else {
- if _, err = keks.Encode(os.Stdout, sign.SignedPrehash{
+ if _, err = keks.Encode(os.Stdout, sign.Prehash{
T: mode.PrehashT,
Sigs: map[string]*struct{}{signer.Algo(): nil},
}, nil); err != nil {
}
var signed sign.Signed
signed.Load.T = *typ
- var sigTbs sign.SigTBS
+ tbs := make(map[string]any)
if !*noWhen {
- when := time.Now().UTC().Truncate(time.Millisecond)
- sigTbs.When = &when
+ tbs["when"] = time.Now().UTC().Truncate(time.Millisecond)
+ }
+ if len(encryptedTo) > 0 {
+ tbs["encrypted-to"] = encryptedTo
}
- sigTbs.EncryptedTo = encryptedTo
- if err = signed.SignWith(pub.PubLoad(), signer, sigTbs); err != nil {
+ if err = signed.SignWith(pub.PubLoad(), signer, tbs); err != nil {
log.Fatal(err)
}
if _, err = keks.Encode(os.Stdout, signed, nil); err != nil {
func usage() {
fmt.Fprintf(os.Stderr, `Usage:
- cmsigtool [-type TYPE] 4<PUB 8<PRV <DATA >DATA.signed
- cmsigtool -verify [-type TYPE] 4<PUB <DATA.signed >DATA
- cmsigtool -detached [-type TYPE] 4<PUB 8<PRV <DATA >DATA.signature
- cmsigtool -detached -verify [-type TYPE] 4<PUB <(cat DATA.signature DATA)
+ cmsigtool [-t TYPE] 4<PUB 8<PRV <DATA >DATA.signed
+ cmsigtool -v [-t TYPE] 4<PUB <DATA.signed >DATA
+ cmsigtool -d [-t TYPE] 4<PUB 8<PRV <DATA >DATA.signature
+ cmsigtool -d -v [-t TYPE] 4<PUB <(cat DATA.signature DATA)
DATA.signed holds completely encapsulated DATA.
--detached mode keeps DATA completely separate.
+-d(etached) mode keeps DATA completely separate.
`)
flag.PrintDefaults()
// Public key load.
type PubLoad struct {
- KU *map[string]*struct{} `keks:"ku,omitempty"`
- Sub map[string]string `keks:"sub"`
- Crit *[]map[string]any `keks:"crit,omitempty"`
- Pub []cm.AV `keks:"pub"`
- Id []byte `keks:"id"`
+ KU map[string]*struct{} `keks:"ku"`
+ Sub map[string]string `keks:"sub"`
+ Crit []map[string]any `keks:"crit"`
+ Pub []cm.AV `keks:"pub"`
+ Id []byte `keks:"id"`
}
// Parse Signed contents as PubLoad (certificate) and check its
return errors.New("PubParse: wrong load type")
}
for _, sig := range signed.Sigs {
- if sig.TBS.CID == nil {
+ if _, ok := sig.TBS["cid"]; !ok {
return errors.New("PubParse: missing cid")
}
- if sig.TBS.Exp == nil {
+ if _, ok := sig.TBS["exp"]; !ok {
return errors.New("PubParse: missing exp")
}
}
var load PubLoad
var err error
if v, ok := (*signed.Load.V).(map[string]any); ok {
+ mapAny := any(v)
+ signed.Load.V = &mapAny
err = keks.Map2Struct(&load, v)
} else {
err = errors.New("PubParse: wrong /load/v")
if err != nil {
return err
}
- {
- loadAny := any(load)
- signed.Load.V = &loadAny
- }
- if load.KU != nil {
- if len(*load.KU) == 0 {
- return errors.New("PubParse: empty ku")
- }
- for _, v := range *load.KU {
- if v != nil {
- return errors.New("PubParse: non-nil ku value")
- }
- }
- }
if len(load.Sub) == 0 {
return errors.New("PubParse: empty sub")
}
- if load.Crit != nil {
- if len(*load.Crit) == 0 {
- return errors.New("PubParse: empty crit")
- }
+ if len(load.Crit) != 0 {
return errors.New("PubParse: currently no critical extensions are supported")
}
if len(load.Pub) == 0 {
// Check if public key has desired ku capability.
func (pub *PubLoad) Can(ku string) (yes bool) {
- if pub.KU == nil {
- return false
- }
- _, yes = (*pub.KU)[ku]
+ _, yes = pub.KU[ku]
return
}
prv Iface,
since, till time.Time,
) error {
- exp := []time.Time{since, till}
cid, err := uuid.NewV7()
if err != nil {
return err
}
- return signed.SignWith(parent, prv, SigTBS{CID: &cid, Exp: &exp})
+ return signed.SignWith(parent, prv, map[string]any{
+ "cid": cid,
+ "exp": []time.Time{since, till},
+ })
}
// Verify signature of signed data. ErrSigInvalid will be returned in
return
}
sig := signed.Sigs[0]
- if !bytes.Equal(sig.TBS.SID, parent.Id) {
+ if !bytes.Equal(sig.TBS["sid"].([]byte), parent.Id) {
err = errors.New("sid != parent pub id")
return
}
if signed.Load.T != "pub" || signed.Load.V == nil {
return nil
}
- l, ok := (*signed.Load.V).(PubLoad)
- if ok {
- return &l
+ v, ok := (*signed.Load.V).(map[string]any)
+ if !ok {
+ return nil
+ }
+ var pubLoad PubLoad
+ err := keks.Map2Struct(&pubLoad, v)
+ if err != nil {
+ return nil
}
- return nil
+ return &pubLoad
}
// Verify signed Signed PubLoad certification against pubs chain of
if len(signed.Sigs) == 0 {
return errors.New("no sigs")
}
+
+ var tbs *TBS
+ tbs, err = signed.Sigs[0].TBSGet()
+ if err != nil {
+ return
+ }
{
- exp := *(signed.Sigs[0].TBS.Exp)
+ exp := tbs.Exp
if t.Before(exp[0]) || t.Equal(exp[0]) {
err = errors.New("pub is not active")
return
return
}
}
- sid := signed.Sigs[0].TBS.SID
+ sid := tbs.SID
if bytes.Equal(sid, signed.PubLoad().Id) {
return signed.CertificationCheckSignatureFrom(signed.PubLoad(), nil)
}
}
signer := idToPub[FPR(sid)]
if signer == nil {
- err = fmt.Errorf("no pub found for sid: %v", signed.Sigs[0].TBS.SID)
+ err = fmt.Errorf("no pub found for sid: %v", tbs.SID)
return
}
err = signed.CertificationCheckSignatureFrom(signer.PubLoad(), nil)
const SignedMagic = keks.Magic("cm/signed")
-type SignedPrehash struct {
+type Prehash struct {
Sigs map[string]*struct{} `keks:"sigs"`
T string `keks:"t"`
}
-type SignedLoad struct {
+type Load struct {
V *any `keks:"v,omitempty"`
T string `keks:"t"`
}
-type SigTBS struct {
- CID *uuid.UUID `keks:"cid,omitempty"`
- Exp *[]time.Time `keks:"exp,omitempty"`
- When *time.Time `keks:"when,omitempty"`
- EncryptedTo [][]byte `keks:"encrypted-to,omitempty"`
- SID []byte `keks:"sid"`
+type TBS struct {
+ EncryptedTo [][]byte `keks:"encrypted-to"`
+ Exp []time.Time `keks:"exp"`
+ SID []byte `keks:"sid"`
+ CID uuid.UUID `keks:"cid"`
}
type Sig struct {
- TBS SigTBS `keks:"tbs"`
- PubLoc *[]string `keks:"pub-loc,omitempty"`
- Sign cm.AV `keks:"sign"`
+ TBS map[string]any `keks:"tbs"`
+ Sign cm.AV `keks:"sign"`
+}
+
+func (sig *Sig) TBSGet() (*TBS, error) {
+ var tbs TBS
+ return &tbs, keks.Map2Struct(&tbs, sig.TBS)
}
type Signed struct {
- Load SignedLoad `keks:"load"`
+ Load Load `keks:"load"`
Pubs *[]*Signed `keks:"pubs,omitempty"`
Sigs []*Sig `keks:"sigs,omitempty"`
}
}
}
for _, sig := range signed.Sigs {
- if sig.PubLoc != nil && len(*sig.PubLoc) == 0 {
- err = errors.New("SignedParse: empty pub-loc")
+ var tbs *TBS
+ tbs, err = sig.TBSGet()
+ if err != nil {
return
}
- if sig.TBS.Exp != nil {
- if len(*sig.TBS.Exp) != 2 {
+ if tbs.Exp != nil {
+ if len(tbs.Exp) != 2 {
err = errors.New("SignedParse: wrong exp len")
return
}
- for _, t := range *sig.TBS.Exp {
+ for _, t := range tbs.Exp {
if t.Nanosecond() != 0 {
err = errors.New("SignedParse: exp with nanoseconds")
return
return
}
-// Sign Signed's contents and sigTBS 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, prv Iface, sigTBS SigTBS) (err error) {
+// Sign Signed's contents and 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,
+ prv Iface,
+ tbs map[string]any,
+) (err error) {
if !parent.Can(KUSig) || len(parent.Pub) != 1 {
return errors.New("parent can not sign")
}
- sigTBS.SID = parent.Id
- var tbs []byte
+ tbs["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 {
return
}
- if _, err = keks.Encode(&b, sigTBS, nil); err != nil {
+ if _, err = keks.Encode(&b, tbs, nil); err != nil {
return
}
- tbs = b.Bytes()
+ tbsRaw = b.Bytes()
} else {
if _, err = keks.Encode(*prv.Prehasher(), signed.Load, nil); err != nil {
return
}
- if _, err = keks.Encode(*prv.Prehasher(), sigTBS, nil); err != nil {
+ if _, err = keks.Encode(*prv.Prehasher(), tbs, nil); err != nil {
return
}
- tbs = (*prv.Prehasher()).Sum(nil)
+ tbsRaw = (*prv.Prehasher()).Sum(nil)
}
- sig := Sig{TBS: sigTBS}
+ sig := Sig{TBS: tbs}
sig.Sign.A = prv.Algo()
- sig.Sign.V, err = prv.Sign(rand.Reader, tbs, crypto.Hash(0))
+ sig.Sign.V, err = prv.Sign(rand.Reader, tbsRaw, crypto.Hash(0))
if err != nil {
return
}