From aae03bb52237329dbfaee2b1ad4ca1ecfd88691c64f7ae027921b4735ca2c474 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Thu, 17 Apr 2025 11:06:29 +0300 Subject: [PATCH] Ability to verify multiple signatures --- go/cm/cmd/cmsigtool/main.go | 123 +++++++++++++++++++++-------------- go/cm/cmd/cmsigtool/usage.go | 4 +- go/cm/sign/pub.go | 46 +++++++------ tcl/schemas/pub-sig-tbs.tcl | 2 +- tcl/schemas/signed.tcl | 2 +- 5 files changed, 101 insertions(+), 76 deletions(-) diff --git a/go/cm/cmd/cmsigtool/main.go b/go/cm/cmd/cmsigtool/main.go index 611f4cd..412c7d9 100644 --- a/go/cm/cmd/cmsigtool/main.go +++ b/go/cm/cmd/cmsigtool/main.go @@ -71,11 +71,20 @@ func main() { fdPubR := os.NewFile(FdPubR, "pub-in") fdPrvR := os.NewFile(FdPrvR, "prv-in") - pub, _, err := sign.PubParse(mustReadAll(fdPubR)) - if err != nil { - log.Fatal(err) + var pubs []*sign.PubLoad + var err error + { + data := mustReadAll(fdPubR) + for len(data) > 0 { + var signed *sign.Signed + signed, data, err = sign.PubParse(data) + if err != nil { + log.Fatal(err) + } + pubs = append(pubs, signed.PubLoad()) + } + fdPubR.Close() } - fdPubR.Close() stdin := bufio.NewReaderSize(os.Stdin, BlobChunkLen) if *verify { @@ -100,16 +109,17 @@ func main() { err = decoder.UnmarshalStruct(&prehash) } var signed sign.Signed - var hasher hash.Hash + hashers := make(map[string]hash.Hash) if err == nil && prehash.T == mode.PrehashT { - if len(prehash.Sigs) > 1 { - log.Fatal("prehash: currently only single signature support") - } + dsts := make([]io.Writer, 0, len(prehash.Sigs)+1) + dsts = append(dsts, os.Stdout) for algo := range prehash.Sigs { - hasher = cmhash.ByName(algo) - } - if hasher == nil { - log.Fatal("prehash: unsupported algorithm") + hasher := cmhash.ByName(algo) + if hasher == nil { + log.Fatalln("prehash: unsupported algorithm:", algo) + } + hashers[algo] = hasher + dsts = append(dsts, hasher) } var blob *keks.BlobDecoder blob, err = keks.NewBlobDecoder(stdin, 1<<32) @@ -117,7 +127,7 @@ func main() { log.Fatal(err) } var chunk []byte - mw := io.MultiWriter(hasher, os.Stdout) + mw := io.MultiWriter(dsts...) for { chunk, err = blob.Next() if err != nil { @@ -144,48 +154,65 @@ func main() { if err != nil { log.Fatal(err) } - if len(signed.Sigs) == 0 { - log.Fatal("no sigs") - } - if len(signed.Sigs) > 1 { - log.Fatal("prehash: currently only single signature support") - } - 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 len(tbs.EncryptedTo) == 0 { - log.Fatal("missing encrypted-to") - } - found := false - for _, their := range tbs.EncryptedTo { - for _, our := range encryptedTo { - if bytes.Equal(our, their) { - found = true - break + for _, sig := range signed.Sigs { + sid := sig.TBS["sid"].([]byte) + var signerFound bool + for _, pub := range pubs { + if !bytes.Equal(sid, pub.Id) { + continue + } + signerFound = true + var tbs *sign.TBS + tbs, err = sig.TBSGet() + if err != nil { + log.Fatal(err) + } + if len(encryptedTo) > 0 { + if len(tbs.EncryptedTo) == 0 { + log.Fatalln(hex.EncodeToString(sid), "missing encrypted-to") + } + found := false + for _, their := range tbs.EncryptedTo { + for _, our := range encryptedTo { + if bytes.Equal(our, their) { + found = true + break + } + } + } + if !found { + log.Fatalln( + hex.EncodeToString(sid), + "corresponding encrypted-to not found") } } + var hasher hash.Hash + if prehash.T == "" { + hasher = cmhash.ByName(sig.Sign.A) + if _, err = io.Copy(hasher, stdin); err != nil { + log.Fatal(hex.EncodeToString(sid), err) + } + } else { + var found bool + hasher, found = hashers[sig.Sign.A] + if !found { + log.Fatalln(hex.EncodeToString(sid), "no hasher in prehash") + } + } + if err = signed.CertificationCheckSignatureFrom( + pub, &hasher, + ); err != nil { + log.Fatalln(hex.EncodeToString(sid), err) + } + break } - if !found { - log.Fatalln("corresponding encrypted-to not found") - } - } - if prehash.T == "" { - hasher = cmhash.ByName(sig.Sign.A) - if _, err = io.Copy(hasher, stdin); err != nil { - log.Fatal(err) + if !signerFound { + log.Fatalln(hex.EncodeToString(sid), "can not find signer") } } - if err = signed.CertificationCheckSignatureFrom(signer, &hasher); err != nil { - log.Fatal(err) - } } else { var signer sign.Iface signer, _, err = sign.PrvParse(mustReadAll(fdPrvR)) @@ -241,7 +268,7 @@ func main() { if len(encryptedTo) > 0 { tbs["encrypted-to"] = encryptedTo } - if err = signed.SignWith(pub.PubLoad(), signer, tbs); err != nil { + if err = signed.SignWith(pubs[0], signer, tbs); err != nil { log.Fatal(err) } if _, err = keks.Encode(os.Stdout, signed, nil); err != nil { diff --git a/go/cm/cmd/cmsigtool/usage.go b/go/cm/cmd/cmsigtool/usage.go index 53b5078..6f50677 100644 --- a/go/cm/cmd/cmsigtool/usage.go +++ b/go/cm/cmd/cmsigtool/usage.go @@ -24,9 +24,9 @@ import ( func usage() { fmt.Fprintf(os.Stderr, `Usage: cmsigtool [-t TYPE] 4DATA.signed - cmsigtool -v [-t TYPE] 4DATA + cmsigtool -v [-t TYPE] 4DATA cmsigtool -d [-t TYPE] 4DATA.signature - cmsigtool -d -v [-t TYPE] 40 optional} - {field when {tai} utc optional} + {field when {tai} utc prec=ms optional} } diff --git a/tcl/schemas/signed.tcl b/tcl/schemas/signed.tcl index 8af5736..e81f2f9 100644 --- a/tcl/schemas/signed.tcl +++ b/tcl/schemas/signed.tcl @@ -21,7 +21,7 @@ tbs { {field . {map}} {field sid {with fpr}} {field nonce {bin} >0 optional} {# random bytes} - {field when {tai} utc optional} + {field when {tai} utc prec=ms optional} {# recipient's fingerprints} {field encrypted-to {list} {of fpr} >0 optional} -- 2.48.1