1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
package policy
import (
"crypto/hmac"
"crypto/sha256"
"encoding/json"
"fmt"
"io"
"golang.org/x/crypto/hkdf"
)
type Node struct {
Name string `json:"name"` // Artbirary node name to authenticate
Secret string `json:"secret"` // Arbitrary node secret for authentication
URL string `json:"location"` // Where the node's submissions can be downloaded
Domains []string `json:"requests"` // Exact-match domain names allowed to be issued
key [16]byte
}
func NewNode(name, secret, url string, domains []string) (Node, error) {
n := Node{Name: name, Secret: secret, Domains: domains, URL: url}
if err := n.deriveKey(); err != nil {
return Node{}, err
}
return n, n.Validate()
}
func (n *Node) UnmarshalJSON(data []byte) error {
type internal Node
if err := json.Unmarshal(data, (*internal)(n)); err != nil {
return err
}
if err := n.deriveKey(); err != nil {
return err
}
return n.Validate()
}
func (n *Node) Validate() error {
if n.Name == "" {
return fmt.Errorf("name is required")
}
if n.Secret == "" {
return fmt.Errorf("secret is required")
}
if n.URL == "" {
return fmt.Errorf("url is required")
}
if n.key == [16]byte{} {
return fmt.Errorf("key needs to be derived")
}
return nil
}
func (n *Node) Authorize(sans []string) error {
for _, san := range sans {
ok := false
for _, domain := range n.Domains {
if domain == san {
ok = true
break
}
}
if !ok {
return fmt.Errorf("node %s is not authorized to issue certificate with name %s", n.Name, san)
}
}
return nil
}
func (n *Node) HMAC(data []byte) (mac [sha256.Size]byte, err error) {
if err = n.Validate(); err != nil {
return
}
h := hmac.New(sha256.New, n.key[:])
_, err = h.Write(data)
copy(mac[:], h.Sum(nil))
return
}
func (n *Node) deriveKey() error {
const salt = "silentct"
hkdf := hkdf.New(sha256.New, []byte(n.Secret), []byte(salt), []byte(n.Name))
_, err := io.ReadFull(hkdf, n.key[:])
return err
}
|