1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 package schema
18
19 import (
20 "context"
21 "errors"
22 "fmt"
23 "io"
24 "os"
25 "strings"
26 "time"
27
28 "perkeep.org/pkg/blob"
29 "perkeep.org/pkg/jsonsign"
30
31 "golang.org/x/crypto/openpgp"
32 )
33
34
35
36 type Signer struct {
37 pubref blob.Ref
38 privEntity *openpgp.Entity
39
40
41
42 baseSigReq jsonsign.SignRequest
43 }
44
45 func (s *Signer) String() string {
46 return fmt.Sprintf("[*schema.Signer for key=%s pubkey=%s]", s.KeyIDLong(), s.pubref)
47 }
48
49
50 func (s *Signer) KeyIDLong() string {
51 return s.privEntity.PrivateKey.KeyIdString()
52 }
53
54
55 func (s *Signer) Entity() *openpgp.Entity {
56 return s.privEntity
57 }
58
59
60
61
62 func NewSigner(pubKeyRef blob.Ref, armoredPubKey io.Reader, privateKeySource interface{}) (*Signer, error) {
63 hash := pubKeyRef.Hash()
64 fingerprint, armoredPubKeyString, err := jsonsign.ParseArmoredPublicKey(io.TeeReader(armoredPubKey, hash))
65 if err != nil {
66 return nil, err
67 }
68 if !pubKeyRef.HashMatches(hash) {
69 return nil, fmt.Errorf("pubkey ref of %v doesn't match provided armored public key", pubKeyRef)
70 }
71
72 var privateKey *openpgp.Entity
73 switch v := privateKeySource.(type) {
74 case *openpgp.Entity:
75 privateKey = v
76 case string:
77 privateKey, err = jsonsign.EntityFromSecring(fingerprint, v)
78 if err != nil {
79 return nil, err
80 }
81 default:
82 return nil, fmt.Errorf("invalid privateKeySource type %T", v)
83 }
84 if privateKey == nil {
85 return nil, errors.New("nil privateKey")
86 }
87
88 return &Signer{
89 pubref: pubKeyRef,
90 privEntity: privateKey,
91 baseSigReq: jsonsign.SignRequest{
92 ServerMode: true,
93 Fetcher: memoryBlobFetcher{
94 pubKeyRef: func() (uint32, io.ReadCloser) {
95 return uint32(len(armoredPubKeyString)), io.NopCloser(strings.NewReader(armoredPubKeyString))
96 },
97 },
98 EntityFetcher: entityFetcherFunc(func(wantFingerprint string) (*openpgp.Entity, error) {
99 if fingerprint != wantFingerprint {
100 return nil, fmt.Errorf("jsonsign code unexpectedly requested fingerprint %q; only have %q",
101 wantFingerprint, fingerprint)
102 }
103 return privateKey, nil
104 }),
105 },
106 }, nil
107 }
108
109
110
111 func (s *Signer) SignJSON(ctx context.Context, json string, t time.Time) (string, error) {
112 sr := s.baseSigReq
113 sr.UnsignedJSON = json
114 sr.SignatureTime = t
115 return sr.Sign(ctx)
116 }
117
118 type memoryBlobFetcher map[blob.Ref]func() (size uint32, rc io.ReadCloser)
119
120 func (m memoryBlobFetcher) Fetch(ctx context.Context, br blob.Ref) (file io.ReadCloser, size uint32, err error) {
121 fn, ok := m[br]
122 if !ok {
123 return nil, 0, os.ErrNotExist
124 }
125 size, file = fn()
126 return
127 }
128
129 type entityFetcherFunc func(keyID string) (*openpgp.Entity, error)
130
131 func (f entityFetcherFunc) FetchEntity(keyID string) (*openpgp.Entity, error) {
132 return f(keyID)
133 }