Skip to content

Commit

Permalink
Release: sign archives with GPG
Browse files Browse the repository at this point in the history
In addition to signing individual executables with platform-specific
methods, sign each archive with GPG. For user convenience, create a
single signature for all archives via a SHA256SUMS file.

Signing archives, particularly the source archive, is important for
software distributions.
  • Loading branch information
strager committed Nov 21, 2021
1 parent a9ecbf7 commit 5fa5003
Showing 1 changed file with 75 additions and 0 deletions.
75 changes: 75 additions & 0 deletions dist/sign-release.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "archive/zip"
import "bytes"
import "compress/gzip"
import "crypto/sha1"
import "crypto/sha256"
import "encoding/hex"
import "errors"
import "flag"
Expand Down Expand Up @@ -60,6 +61,7 @@ func main() {
sourceDir := flag.Args()[0]
destinationDir := flag.Args()[1]

hashes := ListOfHashes{}
err := filepath.Walk(sourceDir, func(sourcePath string, sourceInfo fs.FileInfo, err error) error {
if err != nil {
return err
Expand All @@ -80,6 +82,10 @@ func main() {
if err != nil {
return err
}

if err := hashes.AddHashOfFile(destinationPath, relativePath); err != nil {
return err
}
}
return nil
})
Expand All @@ -90,6 +96,23 @@ func main() {
if err := CheckUnsignedFiles(); err != nil {
log.Fatal(err)
}

hashesPath := filepath.Join(destinationDir, "SHA256SUMS")
if err := hashes.DumpSHA256HashesToFile(hashesPath); err != nil {
log.Fatal(err)
}

log.Printf("signing with GPG: %s\n", hashesPath)
if _, err := GPGSignFile(hashesPath, signingStuff); err != nil {
log.Fatal(err)
}
if err := GPGVerifySignature(hashesPath, hashesPath+".asc", signingStuff); err != nil {
log.Fatal(err)
}

if err := VerifySHA256SUMSFile(hashesPath); err != nil {
log.Fatal(err)
}
}

func RemoveTempDirs() {
Expand Down Expand Up @@ -815,6 +838,58 @@ func WriteTarEntry(header *tar.Header, file io.Reader, output *tar.Writer) error
return nil
}

type ListOfHashes struct {
SHA256Hashes bytes.Buffer
}

func (self *ListOfHashes) AddHashOfFile(path string, name string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
hasher := sha256.New()
if _, err := io.Copy(hasher, file); err != nil {
return err
}
self.SHA256Hashes.WriteString(fmt.Sprintf("%x", hasher.Sum(nil)))
self.SHA256Hashes.WriteString(" ")
self.SHA256Hashes.WriteString(name)
self.SHA256Hashes.WriteString("\n")
return nil
}

func (self *ListOfHashes) DumpSHA256HashesToFile(outPath string) error {
outFile, err := os.Create(outPath)
if err != nil {
return err
}
defer outFile.Close()
data := self.SHA256Hashes.Bytes()
bytesWritten, err := outFile.Write(data)
if err != nil {
return err
}
if bytesWritten != len(data) {
return fmt.Errorf("failed to write entire file")
}
return nil
}

func VerifySHA256SUMSFile(hashesPath string) error {
process := exec.Command("shasum", "--algorithm", "256", "--check", "--", filepath.Base(hashesPath))
process.Stdout = os.Stdout
process.Stderr = os.Stderr
process.Dir = filepath.Dir(hashesPath)
if err := process.Start(); err != nil {
return err
}
if err := process.Wait(); err != nil {
return err
}
return nil
}

// quick-lint-js finds bugs in JavaScript programs.
// Copyright (C) 2020 Matthew "strager" Glazar
//
Expand Down

0 comments on commit 5fa5003

Please sign in to comment.