Updated dependencies; use SafeFile from go-utils. Teach tests.sh to use
a user supplied binary & tmpdir
This commit is contained in:
parent
a538ac8e5c
commit
c4f79962c9
9 changed files with 59 additions and 170 deletions
4
crypt.go
4
crypt.go
|
@ -140,7 +140,7 @@ func encrypt(args []string) {
|
|||
mode = ist.Mode()
|
||||
}
|
||||
|
||||
sf, err := sign.NewSafeFile(outfile, force, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
||||
sf, err := utils.NewSafeFile(outfile, force, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
||||
if err != nil {
|
||||
Die("%s", err)
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ func decrypt(args []string) {
|
|||
mode = ist.Mode()
|
||||
}
|
||||
|
||||
sf, err := sign.NewSafeFile(outfile, force, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
||||
sf, err := utils.NewSafeFile(outfile, force, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
||||
if err != nil {
|
||||
Die("%s", err)
|
||||
}
|
||||
|
|
10
go.mod
10
go.mod
|
@ -1,17 +1,17 @@
|
|||
module github.com/opencoff/sigtool
|
||||
|
||||
go 1.20
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/opencoff/go-utils v0.4.1
|
||||
github.com/opencoff/go-utils v0.7.2
|
||||
github.com/opencoff/pflag v1.0.6-sh1
|
||||
golang.org/x/crypto v0.7.0
|
||||
golang.org/x/crypto v0.15.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/term v0.6.0 // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
golang.org/x/term v0.14.0 // indirect
|
||||
)
|
||||
|
|
17
go.sum
17
go.sum
|
@ -4,18 +4,17 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
|||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/opencoff/go-utils v0.4.1 h1:Ke4Q1Tl2GKMI+dwleuPNHH713ngRiNMOFIkymncHqXg=
|
||||
github.com/opencoff/go-utils v0.4.1/go.mod h1:c+7QUAiCCHcNH6OGvsZ0fviG7cgse8Y3ucg+xy7sGXM=
|
||||
github.com/opencoff/go-utils v0.7.2 h1:FK250pZ9UH+zdp1DlGyRARq7nULHEIkTVbpITTwwVXk=
|
||||
github.com/opencoff/go-utils v0.7.2/go.mod h1:8hMC3uc+N0wUMxpmW2yzM6FuhlCCxRST1Wj+cYntqFA=
|
||||
github.com/opencoff/pflag v1.0.6-sh1 h1:6RO8GgnpH928yu6earGDD01FnFT//bDJ1hCovcVVqY4=
|
||||
github.com/opencoff/pflag v1.0.6-sh1/go.mod h1:2bXtpAD/5h/2LarkbsRwiUxqnvB1nZBzn9Xjad1P41A=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
|
@ -28,10 +27,10 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
|
||||
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
|
@ -753,6 +753,7 @@ func (d *Decryptor) verifySender(key []byte, senderPk *PublicKey) error {
|
|||
}
|
||||
|
||||
// Wrap data encryption key 'k' with the sender's PK and our ephemeral curve SK
|
||||
//
|
||||
// basically, we do a scalarmult: Ephemeral encryption/decryption SK x receiver PK
|
||||
func (e *Encryptor) wrapKey(pk *PublicKey) (*pb.WrappedKey, error) {
|
||||
rxPK := pk.ToCurve25519PK()
|
||||
|
|
|
@ -503,7 +503,7 @@ func (pk *PublicKey) UnmarshalBinary(yml []byte) error {
|
|||
// Does MORE than ioutil.WriteFile() - in that it doesn't trash the
|
||||
// existing file with an incomplete write.
|
||||
func writeFile(fn string, b []byte, ovwrite bool, mode uint32) error {
|
||||
sf, err := NewSafeFile(fn, ovwrite, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(mode))
|
||||
sf, err := utils.NewSafeFile(fn, ovwrite, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
124
sign/safefile.go
124
sign/safefile.go
|
@ -1,124 +0,0 @@
|
|||
// safefile.go - safe file creation and unwinding on error
|
||||
//
|
||||
// (c) 2021 Sudhi Herle <sudhi@herle.net>
|
||||
//
|
||||
// Licensing Terms: GPLv2
|
||||
//
|
||||
// If you need a commercial license for this work, please contact
|
||||
// the author.
|
||||
//
|
||||
// This software does not come with any express or implied
|
||||
// warranty; it is provided "as is". No claim is made to its
|
||||
// suitability for any purpose.
|
||||
|
||||
package sign
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// SafeFile is an io.WriteCloser which uses a temporary file that
|
||||
// will be atomically renamed when there are no errors and
|
||||
// caller invokes Close(). Callers are advised to call
|
||||
// Abort() in the appropriate error handling (defer) context
|
||||
// so that the temporary file is properly deleted.
|
||||
type SafeFile struct {
|
||||
*os.File
|
||||
|
||||
// error for writes recorded once
|
||||
err error
|
||||
name string // actual filename
|
||||
|
||||
closed bool // set if the file is closed properly
|
||||
}
|
||||
|
||||
var _ io.WriteCloser = &SafeFile{}
|
||||
|
||||
// NewSafeFile creates a new temporary file that would either be
|
||||
// aborted or safely renamed to the correct name.
|
||||
// 'nm' is the name of the final file; if 'ovwrite' is true,
|
||||
// then the file is overwritten if it exists.
|
||||
func NewSafeFile(nm string, ovwrite bool, flag int, perm os.FileMode) (*SafeFile, error) {
|
||||
if _, err := os.Stat(nm); err == nil && !ovwrite {
|
||||
return nil, fmt.Errorf("safefile: won't overwrite existing %s", nm)
|
||||
}
|
||||
|
||||
// forcibly unlink the old file - so previous artifacts don't exist
|
||||
os.Remove(nm)
|
||||
|
||||
tmp := fmt.Sprintf("%s.tmp.%d.%x", nm, os.Getpid(), randu32())
|
||||
fd, err := os.OpenFile(tmp, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sf := &SafeFile{
|
||||
File: fd,
|
||||
name: nm,
|
||||
}
|
||||
return sf, nil
|
||||
}
|
||||
|
||||
// Attempt to write everything in 'b' and don't proceed if there was
|
||||
// a previous error or the file was already closed.
|
||||
func (sf *SafeFile) Write(b []byte) (int, error) {
|
||||
if sf.err != nil {
|
||||
return 0, sf.err
|
||||
}
|
||||
|
||||
if sf.closed {
|
||||
return 0, fmt.Errorf("safefile: %s is closed", sf.Name())
|
||||
}
|
||||
|
||||
var z, nw int
|
||||
n := len(b)
|
||||
for n > 0 {
|
||||
if nw, sf.err = sf.File.Write(b); sf.err != nil {
|
||||
return z, sf.err
|
||||
}
|
||||
z += nw
|
||||
n -= nw
|
||||
b = b[nw:]
|
||||
}
|
||||
return z, nil
|
||||
}
|
||||
|
||||
// Abort the file write and remove any temporary artifacts
|
||||
func (sf *SafeFile) Abort() {
|
||||
// if we've successfully closed, nothing to do!
|
||||
if sf.closed {
|
||||
return
|
||||
}
|
||||
|
||||
sf.closed = true
|
||||
sf.File.Close()
|
||||
os.Remove(sf.Name())
|
||||
}
|
||||
|
||||
// Close flushes all file data & metadata to disk, closes the file and atomically renames
|
||||
// the temp file to the actual file - ONLY if there were no intervening errors.
|
||||
func (sf *SafeFile) Close() error {
|
||||
if sf.err != nil {
|
||||
sf.Abort()
|
||||
return sf.err
|
||||
}
|
||||
|
||||
// mark this file as closed!
|
||||
sf.closed = true
|
||||
|
||||
if sf.err = sf.Sync(); sf.err != nil {
|
||||
return sf.err
|
||||
}
|
||||
|
||||
if sf.err = sf.File.Close(); sf.err != nil {
|
||||
return sf.err
|
||||
}
|
||||
|
||||
if sf.err = os.Rename(sf.Name(), sf.name); sf.err != nil {
|
||||
return sf.err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -38,6 +38,7 @@ type Signature struct {
|
|||
|
||||
// Sign a prehashed Message; return the signature as opaque bytes
|
||||
// Signature is an YAML file:
|
||||
//
|
||||
// Comment: source file path
|
||||
// Signature: Ed25519 signature
|
||||
func (sk *PrivateKey) SignMessage(ck []byte, comment string) (*Signature, error) {
|
||||
|
|
|
@ -213,7 +213,7 @@ Options:
|
|||
var fd io.WriteCloser = os.Stdout
|
||||
|
||||
if outf != "-" {
|
||||
sf, err := sign.NewSafeFile(outf, force, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
||||
sf, err := utils.NewSafeFile(outf, force, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
Die("can't create sig file: %s", err)
|
||||
}
|
||||
|
|
52
tests.sh
52
tests.sh
|
@ -1,32 +1,44 @@
|
|||
#! /usr/bin/env bash
|
||||
|
||||
|
||||
# simple round-trip tests to verify the tool
|
||||
# Usage:
|
||||
# $0 [bin=/path/to/sigtool] [tmpdir=/path/to/workdir]
|
||||
|
||||
# Use cmdline flag to get go-root
|
||||
|
||||
GoRoot=$HOME/go
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
GoRoot=$1
|
||||
fi
|
||||
|
||||
arch=`./build --go-root=$GoRoot --print-arch`
|
||||
bin=./bin/$arch/sigtool
|
||||
Z=`basename $0`
|
||||
|
||||
# workdir
|
||||
tmpdir=/tmp/sigtool$$
|
||||
|
||||
die() {
|
||||
echo "$Z: $@" 1>&2
|
||||
echo "$Z: Test output in $tmpdir .." 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# cmd line args processing
|
||||
for a in $*; do
|
||||
key=${a%=*}
|
||||
val=${a#*=}
|
||||
case $key in
|
||||
bin)
|
||||
bin=$val
|
||||
;;
|
||||
|
||||
tmpdir)
|
||||
tmpdir=$val
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Ignoring $key .."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$bin" ]; then
|
||||
arch=`./build --print-arch`
|
||||
bin=./bin/$arch/sigtool
|
||||
|
||||
[ -x $bin ] || ./build || die "can't find & build sigtool"
|
||||
fi
|
||||
|
||||
[ -z "$tmpdir" ] && tmpdir=/tmp/sigtool$$
|
||||
|
||||
mkdir -p $tmpdir || die "can't mkdir $tmpdir"
|
||||
[ -x $bin ] || ./build || die "Can't build sigtool for $arch"
|
||||
|
||||
# env name for reading the password
|
||||
passenv=FOO
|
||||
|
@ -38,9 +50,9 @@ FOO=bar
|
|||
#trap "rm -rf $tmpdir" EXIT
|
||||
|
||||
bn=$tmpdir/foo
|
||||
sig=$tmpdir/$Z.sig
|
||||
pk=$bn.pub
|
||||
sk=$bn.key
|
||||
sig=$tmpdir/$Z.sig
|
||||
bn2=$tmpdir/bar
|
||||
pk2=$bn2.pub
|
||||
sk2=$bn2.key
|
||||
|
@ -77,14 +89,14 @@ rm -f $sig $encout $decout
|
|||
|
||||
# generate keys
|
||||
$bin g -E FOO $bn || die "can't gen keypair $pk, $sk"
|
||||
$bin g -E FOO $bn && die "overwrote prev keypair"
|
||||
$bin g -E FOO $bn 2>/dev/null && die "overwrote prev keypair"
|
||||
$bin g -E FOO --overwrite $bn || die "can't force gen keypair $pk, $sk"
|
||||
$bin g -E FOO $bn2 || die "can't force gen keypair $pk2, $sk2"
|
||||
|
||||
# sign and verify
|
||||
$bin s -E FOO $sk $0 -o $sig || die "can't sign $0"
|
||||
$bin v -q $pk $sig $0 || die "can't verify signature of $0"
|
||||
$bin v -q $pk2 $sig $0 && die "bad verification with wrong $pk2"
|
||||
$bin v -q $pk2 $sig $0 2>/dev/null && die "bad verification with wrong $pk2"
|
||||
|
||||
# encrypt/decrypt
|
||||
$bin e -E FOO -o $encout $pk2 $0 || die "can't encrypt to $pk2"
|
||||
|
|
Loading…
Add table
Reference in a new issue