1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 package jsonsign
18
19 import (
20 "bytes"
21 "errors"
22 "fmt"
23 "io"
24 "os"
25 "path/filepath"
26 "strings"
27
28 "perkeep.org/internal/osutil"
29
30 "go4.org/wkfs"
31 "golang.org/x/crypto/openpgp"
32 "golang.org/x/crypto/openpgp/armor"
33 "golang.org/x/crypto/openpgp/packet"
34 )
35
36 const publicKeyMaxSize = 256 * 1024
37
38
39
40
41
42 func ParseArmoredPublicKey(r io.Reader) (fingerprint, armoredKey string, err error) {
43 var buf bytes.Buffer
44 pk, err := openArmoredPublicKeyFile(io.NopCloser(io.TeeReader(r, &buf)))
45 if err != nil {
46 return
47 }
48 return fingerprintString(pk), buf.String(), nil
49 }
50
51
52
53 func fingerprintString(pubKey *packet.PublicKey) string {
54 return fmt.Sprintf("%X", pubKey.Fingerprint)
55 }
56
57 func openArmoredPublicKeyFile(reader io.ReadCloser) (*packet.PublicKey, error) {
58 defer reader.Close()
59
60 var lr = io.LimitReader(reader, publicKeyMaxSize)
61 block, _ := armor.Decode(lr)
62 if block == nil {
63 return nil, errors.New("Couldn't find PGP block in public key file")
64 }
65 if block.Type != "PGP PUBLIC KEY BLOCK" {
66 return nil, errors.New("invalid public key blob")
67 }
68 p, err := packet.Read(block.Body)
69 if err != nil {
70 return nil, fmt.Errorf("Invalid public key blob: %v", err)
71 }
72
73 pk, ok := p.(*packet.PublicKey)
74 if !ok {
75 return nil, fmt.Errorf("Invalid public key blob; not a public key packet")
76 }
77 return pk, nil
78 }
79
80
81
82 func EntityFromSecring(keyID, keyFile string) (*openpgp.Entity, error) {
83 if keyID == "" {
84 return nil, errors.New("empty keyID passed to EntityFromSecring")
85 }
86 keyID = strings.ToUpper(keyID)
87 if keyFile == "" {
88 keyFile = osutil.SecretRingFile()
89 }
90 secring, err := wkfs.Open(keyFile)
91 if err != nil {
92 return nil, fmt.Errorf("jsonsign: failed to open keyring: %v", err)
93 }
94 defer secring.Close()
95
96 el, err := readKeyRing(secring)
97 if err != nil {
98 return nil, fmt.Errorf("readKeyRing of %q: %v", keyFile, err)
99 }
100 var entity *openpgp.Entity
101 for _, e := range el {
102 pk := e.PrivateKey
103 if pk == nil || (keyID != fmt.Sprintf("%X", pk.Fingerprint) &&
104 pk.KeyIdString() != keyID &&
105 pk.KeyIdShortString() != keyID) {
106 continue
107 }
108 entity = e
109 }
110 if entity == nil {
111 found := []string{}
112 for _, e := range el {
113 pk := e.PrivateKey
114 if pk == nil {
115 continue
116 }
117 found = append(found, pk.KeyIdString())
118 }
119 return nil, fmt.Errorf("didn't find a key in %q for keyID %q; other keyIDs in file = %v", keyFile, keyID, found)
120 }
121 return entity, nil
122 }
123
124 var newlineBytes = []byte("\n")
125
126 func ArmoredPublicKey(entity *openpgp.Entity) (string, error) {
127 var buf bytes.Buffer
128 wc, err := armor.Encode(&buf, openpgp.PublicKeyType, nil)
129 if err != nil {
130 return "", err
131 }
132 err = entity.PrivateKey.PublicKey.Serialize(wc)
133 if err != nil {
134 return "", err
135 }
136 wc.Close()
137 if !bytes.HasSuffix(buf.Bytes(), newlineBytes) {
138 buf.WriteString("\n")
139 }
140 return buf.String(), nil
141 }
142
143
144 func NewEntity() (*openpgp.Entity, error) {
145 name := ""
146 comment := "camlistore"
147 email := ""
148 return openpgp.NewEntity(name, comment, email, nil)
149 }
150
151 func WriteKeyRing(w io.Writer, el openpgp.EntityList) error {
152 armoredWriter, err := armor.Encode(w, openpgp.PrivateKeyType, nil)
153 if err != nil {
154 return err
155 }
156 for _, ent := range el {
157 if err := ent.SerializePrivate(armoredWriter, nil); err != nil {
158 return err
159 }
160 }
161 return armoredWriter.Close()
162 }
163
164
165 func readKeyRing(r io.Reader) (openpgp.EntityList, error) {
166 var buffer bytes.Buffer
167 if el, err := openpgp.ReadArmoredKeyRing(io.TeeReader(r, &buffer)); err == nil {
168 return el, err
169 }
170 return openpgp.ReadKeyRing(&buffer)
171 }
172
173
174
175
176 func KeyIdFromRing(secRing string) (keyID string, err error) {
177 f, err := wkfs.Open(secRing)
178 if err != nil {
179 return "", fmt.Errorf("Could not open secret ring file %v: %v", secRing, err)
180 }
181 defer f.Close()
182 el, err := readKeyRing(f)
183 if err != nil {
184 return "", fmt.Errorf("Could not read secret ring file %s: %v", secRing, err)
185 }
186 if len(el) != 1 {
187 return "", fmt.Errorf("Secret ring file %v contained %d identities; expected 1", secRing, len(el))
188 }
189 ent := el[0]
190 return ent.PrimaryKey.KeyIdString(), nil
191 }
192
193
194
195
196 func GenerateNewSecRing(secRing string) (keyID string, err error) {
197 ent, err := NewEntity()
198 if err != nil {
199 return "", fmt.Errorf("generating new identity: %v", err)
200 }
201 if err := os.MkdirAll(filepath.Dir(secRing), 0700); err != nil {
202 return "", err
203 }
204 f, err := wkfs.OpenFile(secRing, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
205 if err != nil {
206 return "", err
207 }
208 err = WriteKeyRing(f, openpgp.EntityList([]*openpgp.Entity{ent}))
209 if err != nil {
210 f.Close()
211 return "", fmt.Errorf("Could not write new key ring to %s: %v", secRing, err)
212 }
213 if err := f.Close(); err != nil {
214 return "", fmt.Errorf("Could not close %v: %v", secRing, err)
215 }
216 return ent.PrimaryKey.KeyIdString(), nil
217 }