1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package pgptools
18
19 import (
20 "bufio"
21 "bytes"
22 "crypto"
23 "errors"
24 "io"
25 "io/ioutil"
26
27 "golang.org/x/crypto/openpgp"
28 "golang.org/x/crypto/openpgp/armor"
29 "golang.org/x/crypto/openpgp/clearsign"
30 "golang.org/x/crypto/openpgp/packet"
31 )
32
33 var sigHeader = []byte("-----BEGIN PGP SIGNATURE-----")
34 var crlf = []byte("\r\n")
35
36
37 func ClearSign(w io.Writer, signer *openpgp.Entity, message io.Reader, config *packet.Config) error {
38 e, err := clearsign.Encode(w, signer.PrivateKey, config)
39 if err != nil {
40 return err
41 }
42 if _, err := io.Copy(e, message); err != nil {
43 return err
44 }
45 if err := e.Close(); err != nil {
46 return err
47 }
48 _, err = w.Write(crlf)
49 return err
50 }
51
52
53
54 func DetachClearSign(w io.Writer, signer *openpgp.Entity, message io.Reader, config *packet.Config) error {
55 readPipe, writePipe := io.Pipe()
56 done := make(chan error)
57 go func() {
58 tail, err := tailClearSign(readPipe)
59 if err == nil {
60 w.Write(tail)
61 }
62 done <- err
63 }()
64 err := ClearSign(writePipe, signer, message, config)
65 writePipe.CloseWithError(err)
66 return <-done
67 }
68
69
70 func tailClearSign(r io.Reader) ([]byte, error) {
71 s := bufio.NewScanner(r)
72 out := bytes.NewBuffer(make([]byte, 0, 1024))
73 copying := false
74 for s.Scan() {
75 line := s.Bytes()
76 if copying || bytes.Equal(line, sigHeader) {
77 copying = true
78 out.Write(line)
79 out.WriteString("\r\n")
80 }
81 }
82 return out.Bytes(), s.Err()
83 }
84
85
86
87 func MergeClearSign(w io.Writer, sig []byte, message io.Reader) error {
88 config, err := configFromSig(sig)
89 if err != nil {
90 return err
91 }
92
93 signer := &openpgp.Entity{PrivateKey: &packet.PrivateKey{
94 PrivateKey: fakeSigner{},
95 PublicKey: packet.PublicKey{PubKeyAlgo: packet.PubKeyAlgoRSA},
96 }}
97
98 out := bufio.NewWriter(w)
99 defer out.Flush()
100 readPipe, writePipe := io.Pipe()
101 done := make(chan error)
102 go func() {
103 done <- headClearSign(readPipe, out)
104 }()
105
106 err = ClearSign(writePipe, signer, message, config)
107 writePipe.CloseWithError(err)
108 if err := <-done; err != nil {
109 return err
110 }
111
112 _, err = out.Write(sig)
113 return err
114 }
115
116
117 func headClearSign(r io.Reader, w io.Writer) error {
118 s := bufio.NewScanner(r)
119 for s.Scan() {
120 line := s.Bytes()
121 if bytes.Equal(line, sigHeader) {
122
123 _, err := io.Copy(ioutil.Discard, r)
124 return err
125 }
126 if _, err := w.Write(line); err != nil {
127 return err
128 }
129 if _, err := w.Write(crlf); err != nil {
130 return err
131 }
132 }
133 if s.Err() != nil {
134 return s.Err()
135 }
136 return errors.New("Signature block not found")
137 }
138
139
140
141 func configFromSig(sigarmor []byte) (*packet.Config, error) {
142 block, err := armor.Decode(bytes.NewReader(sigarmor))
143 if err != nil {
144 return nil, err
145 }
146 if block.Type != "PGP SIGNATURE" {
147 return nil, errors.New("Not a PGP signature")
148 }
149 parser := packet.NewReader(block.Body)
150 pkt, err := parser.Next()
151 if err != nil {
152 return nil, errors.New("Not a PGP signature")
153 }
154 var hashFunc crypto.Hash
155 switch sig := pkt.(type) {
156 case *packet.Signature:
157 hashFunc = sig.Hash
158 case *packet.SignatureV3:
159 hashFunc = sig.Hash
160 default:
161 return nil, errors.New("Not a PGP signature")
162 }
163 return &packet.Config{DefaultHash: hashFunc}, nil
164 }
165
166 type fakeSigner struct{}
167
168 func (fakeSigner) Public() crypto.PublicKey {
169 return nil
170 }
171
172 func (fakeSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
173 return []byte("fake signature here"), nil
174 }
175
View as plain text