diff options
Diffstat (limited to 'pkg/policy/node.go')
| -rw-r--r-- | pkg/policy/node.go | 93 | 
1 files changed, 93 insertions, 0 deletions
diff --git a/pkg/policy/node.go b/pkg/policy/node.go new file mode 100644 index 0000000..23f04ca --- /dev/null +++ b/pkg/policy/node.go @@ -0,0 +1,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 +}  | 
