1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package signdeb
18
19 import (
20 "bytes"
21 "crypto"
22 "errors"
23 "fmt"
24 "io"
25 "io/ioutil"
26 "path"
27 "strings"
28 "time"
29
30 "github.com/sassoftware/relic/lib/binpatch"
31 "github.com/sassoftware/relic/lib/pgptools"
32 "github.com/sassoftware/relic/lib/readercounter"
33
34 "github.com/qur/ar"
35 "golang.org/x/crypto/openpgp"
36 "golang.org/x/crypto/openpgp/packet"
37 )
38
39 type DebSignature struct {
40 Info PackageInfo
41 CreationTime time.Time
42 PatchSet *binpatch.PatchSet
43 }
44
45
46
47
48 func Sign(r io.Reader, signer *openpgp.Entity, opts crypto.SignerOpts, role string) (*DebSignature, error) {
49 counter := readercounter.New(r)
50 now := time.Now().UTC()
51 reader := ar.NewReader(counter)
52 msg := new(bytes.Buffer)
53 fmt.Fprintln(msg, "Version: 4")
54 fmt.Fprintln(msg, "Signer:", pgptools.EntityName(signer))
55 fmt.Fprintln(msg, "Date:", now.Format(time.ANSIC))
56 fmt.Fprintln(msg, "Role:", role)
57 fmt.Fprintln(msg, "Files: ")
58 var patchOffset, patchLength int64
59 var info *PackageInfo
60 filename := "_gpg" + role
61 for {
62 hdr, err := reader.Next()
63 if err == io.EOF {
64 break
65 } else if err != nil {
66 return nil, err
67 }
68 name := path.Clean(hdr.Name)
69 if name == filename {
70
71 patchOffset = counter.N - 60
72 patchLength = int64(60 + ((hdr.Size+1)/2)*2)
73 }
74 if strings.HasPrefix(name, "_gpg") {
75 continue
76 }
77 save := io.Writer(ioutil.Discard)
78 var closer io.Closer
79 var infoch chan *PackageInfo
80 var errch chan error
81 if strings.HasPrefix(name, "control.tar") {
82
83 ext := name[11:]
84 r, w := io.Pipe()
85 save = w
86 closer = w
87 infoch = make(chan *PackageInfo, 1)
88 errch = make(chan error, 1)
89 go func() {
90 info, err := parseControl(r, ext)
91
92 _, _ = io.Copy(ioutil.Discard, r)
93 infoch <- info
94 errch <- err
95 }()
96 }
97 md5 := crypto.MD5.New()
98 sha1 := crypto.SHA1.New()
99 if _, err := io.Copy(io.MultiWriter(md5, sha1, save), reader); err != nil {
100 return nil, err
101 }
102 if closer != nil {
103 closer.Close()
104 }
105 fmt.Fprintf(msg, "\t%x %x %d %s\n", md5.Sum(nil), sha1.Sum(nil), hdr.Size, hdr.Name)
106 if errch != nil {
107
108 info = <-infoch
109 if err := <-errch; err != nil {
110 return nil, err
111 }
112 }
113 }
114 if info == nil {
115 return nil, errors.New("deb has no control.tar")
116 }
117 fmt.Fprintln(msg)
118 signed := new(bytes.Buffer)
119 config := &packet.Config{
120 DefaultHash: opts.HashFunc(),
121 Time: func() time.Time { return now },
122 }
123 if err := pgptools.ClearSign(signed, signer, msg, config); err != nil {
124 return nil, err
125 }
126
127
128 pbuf := new(bytes.Buffer)
129 writer := ar.NewWriter(pbuf)
130 hdr := &ar.Header{
131 Name: filename,
132 Size: int64(signed.Len()),
133 ModTime: now,
134 Mode: 0100644,
135 }
136 if err := writer.WriteHeader(hdr); err != nil {
137 return nil, err
138 }
139 if _, err := writer.Write(signed.Bytes()); err != nil {
140 return nil, err
141 }
142 if patchOffset == 0 {
143 patchOffset = counter.N
144 }
145 patch := binpatch.New()
146 patch.Add(patchOffset, patchLength, pbuf.Bytes())
147 return &DebSignature{*info, now, patch}, nil
148 }
149
View as plain text