// Copyright 2017 Debpkg authors. All rights reserved. // Use of this source code is governed by the MIT // license that can be found in the LICENSE file. package debpkg import ( "bytes" "crypto" "crypto/md5" "crypto/sha1" "fmt" "hash" "io" "os" "time" "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/clearsign" "golang.org/x/crypto/openpgp/packet" ) const digestDefaultHash = crypto.SHA1 const digestVersion = 4 const digestRole = "builder" // Digest file for GPG signing type digest struct { plaintext string // Plaintext package digest (empty when unsigned) clearsign string // GPG clearsigned package digest (empty when unsigned) signer string // Name date string // Mon Jan 2 15:04:05 2006 (time.ANSIC) files string // Multiple "\t " // E.g: // 3cf918272ffa5de195752d73f3da3e5e 7959c969e092f2a5a8604e2287807ac5b1b384ad 4 debian-binary // 79bb73dbb522dc1a2dd1b9c2ec89fc79 26d29d15aad5c0e051d07571e28da2bc0009707e 366 control.tar.gz // e1a6e48c95a760170029ef7872cec994 e02ed99e5c4fd847bde12b4c2c30dd814b26ec27 136 data.tar.gz } // Create unsigned digest file at toplevel of deb package // NOTE: the deb.digest.version and deb.digest.role are set in this function! func createDigestFileString(deb *DebPkg) string { const digestFileTmpl = `Version: %d Signer: %s Date: %s Role: %s Files: %s` // debian-binary md5sum, _ := digestCalcDataHash(bytes.NewBuffer([]byte(deb.debianBinary)), md5.New()) sha1sum, _ := digestCalcDataHash(bytes.NewBuffer([]byte(deb.debianBinary)), sha1.New()) deb.digest.files += fmt.Sprintf("\t%x %x %d %s\n", md5sum, sha1sum, len(deb.debianBinary), "debian-binary") deb.digestAddFile("control.tar.gz", deb.control.tgz.Name(), deb.control.tgz.Size()) deb.digestAddFile("data.tar.gz", deb.data.tgz.Name(), deb.data.tgz.Size()) return fmt.Sprintf(digestFileTmpl, digestVersion, deb.digest.signer, deb.digest.date, digestRole, deb.digest.files) } func (deb *DebPkg) digestAddFile(filename, filepath string, size int64) { md5sum, _ := digestCalcDataHashFromFile(filepath, md5.New()) sha1sum, _ := digestCalcDataHashFromFile(filepath, sha1.New()) deb.digest.files += fmt.Sprintf("\t%x %x %d %s\n", md5sum, sha1sum, size, filename) } func digestCalcDataHashFromFile(filename string, hash hash.Hash) (string, error) { f, err := os.Open(filename) if err != nil { return "", err } defer f.Close() return digestCalcDataHash(f, hash) } func digestCalcDataHash(in io.Reader, hash hash.Hash) (string, error) { var result []byte if _, err := io.Copy(hash, in); err != nil { return "", err } return string(hash.Sum(result)), nil } // WriteSigned package with GPG entity func (deb *DebPkg) WriteSigned(filename string, entity *openpgp.Entity) error { var buf bytes.Buffer var cfg packet.Config var signer string cfg.DefaultHash = digestDefaultHash for id := range entity.Identities { // TODO real search for keyid, need to investigate maybe a subkey? signer = id } deb.digest.date = time.Now().Format(time.ANSIC) deb.digest.signer = signer clearsign, err := clearsign.Encode(&buf, entity.PrivateKey, &cfg) if err != nil { return fmt.Errorf("error while signing: %s", err) } if err := deb.writeControlData(); err != nil { return err } deb.digest.plaintext = createDigestFileString(deb) if _, err = clearsign.Write([]byte(deb.digest.plaintext)); err != nil { return fmt.Errorf("error from Write: %s", err) } if err = clearsign.Close(); err != nil { return fmt.Errorf("error from Close: %s", err) } deb.digest.clearsign = buf.String() if filename == "" { filename = deb.GetFilename() } return deb.createDebAr(filename) }