1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package worker
18
19 import (
20 "bytes"
21 "context"
22 "crypto"
23 "crypto/rsa"
24 "crypto/x509"
25 "encoding/json"
26 "errors"
27 "io"
28 "io/ioutil"
29 "net/http"
30 "net/url"
31 "time"
32
33 "github.com/sassoftware/relic/config"
34 "github.com/sassoftware/relic/internal/workerrpc"
35 "github.com/sassoftware/relic/token"
36 )
37
38 const (
39 defaultRetries = 5
40 defaultTimeout = 60 * time.Second
41 )
42
43 func (t *WorkerToken) request(ctx context.Context, path string, rr workerrpc.Request) (*workerrpc.Response, error) {
44 req := &http.Request{
45 Method: http.MethodPost,
46 URL: &url.URL{Scheme: "http", Host: t.addr, Path: path},
47 Header: http.Header{"Auth-Cookie": []string{t.cookie}},
48 }
49 blob, err := json.Marshal(rr)
50 if err != nil {
51 return nil, err
52 }
53 req.GetBody = func() (io.ReadCloser, error) {
54 return ioutil.NopCloser(bytes.NewReader(blob)), nil
55 }
56 return t.doRetry(req.WithContext(ctx))
57 }
58
59 func (t *WorkerToken) Ping() error {
60 return t.PingContext(context.Background())
61 }
62
63 func (t *WorkerToken) PingContext(ctx context.Context) error {
64 _, err := t.request(ctx, workerrpc.Ping, workerrpc.Request{})
65 return err
66 }
67
68 func (t *WorkerToken) Config() *config.TokenConfig {
69 return t.tconf
70 }
71
72 func (t *WorkerToken) GetKey(keyName string) (token.Key, error) {
73 return t.GetKeyContext(context.Background(), keyName)
74 }
75
76 func (t *WorkerToken) GetKeyContext(ctx context.Context, keyName string) (token.Key, error) {
77 kconf, err := t.config.GetKey(keyName)
78 if err != nil {
79 return nil, err
80 }
81 res, err := t.request(ctx, workerrpc.GetKey, workerrpc.Request{KeyName: kconf.Name()})
82 if err != nil {
83 return nil, err
84 }
85 pub, err := x509.ParsePKIXPublicKey(res.Value)
86 if err != nil {
87 return nil, err
88 }
89 return &workerKey{
90 token: t,
91 kconf: kconf,
92 public: pub,
93 id: res.ID,
94 }, nil
95 }
96
97 func (t *WorkerToken) Import(keyName string, privKey crypto.PrivateKey) (token.Key, error) {
98 return nil, errors.New("function not implemented for worker token")
99 }
100
101 func (t *WorkerToken) ImportCertificate(cert *x509.Certificate, labelBase string) error {
102 return errors.New("function not implemented for worker token")
103 }
104
105 func (t *WorkerToken) Generate(keyName string, keyType token.KeyType, bits uint) (token.Key, error) {
106 return nil, errors.New("function not implemented for worker token")
107 }
108
109 func (t *WorkerToken) ListKeys(opts token.ListOptions) error {
110 return errors.New("function not implemented for worker token")
111 }
112
113 type workerKey struct {
114 token *WorkerToken
115 kconf *config.KeyConfig
116 public crypto.PublicKey
117 id []byte
118 }
119
120 func (k *workerKey) Config() *config.KeyConfig {
121 return k.kconf
122 }
123
124 func (k *workerKey) Public() crypto.PublicKey {
125 return k.public
126 }
127
128 func (k *workerKey) GetID() []byte {
129 return k.id
130 }
131
132 func (k *workerKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
133 return k.SignContext(context.Background(), digest, opts)
134 }
135
136 func (k *workerKey) SignContext(ctx context.Context, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
137 rr := workerrpc.Request{
138 KeyName: k.kconf.Name(),
139 Digest: digest,
140 }
141 if opts != nil {
142 rr.Hash = uint(opts.HashFunc())
143 if o, ok := opts.(*rsa.PSSOptions); ok {
144 rr.SaltLength = &o.SaltLength
145 }
146 }
147 res, err := k.token.request(ctx, workerrpc.Sign, rr)
148 if err != nil {
149 return nil, err
150 }
151 return res.Value, nil
152 }
153
154 func (k *workerKey) ImportCertificate(cert *x509.Certificate) error {
155 return errors.New("function not implemented for worker token")
156 }
157
View as plain text