aboutsummaryrefslogtreecommitdiff
path: root/pkg/policy/node.go
blob: 23f04ca25a199787e7b4a0e76f4f2ea4076d8c59 (plain)
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:"url"`    // Where the node's submissions can be downloaded
	Domains []string `json:"issues"` // 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 = "silent-ct"

	hkdf := hkdf.New(sha256.New, []byte(n.Secret), []byte(salt), []byte(n.Name))
	_, err := io.ReadFull(hkdf, n.key[:])

	return err
}