carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package hostevidence
2
3import (
4 "bytes"
5 "context"
6 "crypto/ed25519"
7 "errors"
8 "strings"
9
10 "github.com/carlosframework/platform/internal/release"
11)
12
13var ErrSignature = errors.New("hostevidence: invalid receipt signature")
14
15func message(key string, body []byte) ([]byte, error) {
16 parts := strings.Split(key, "/")
17 if len(parts) < 6 || parts[0] != "control" || parts[1] != "hosts" ||
18 !((len(parts) == 7 && parts[3] == "evidence") || (len(parts) == 6 && parts[3] == "serving-evidence")) ||
19 !strings.HasSuffix(key, ".json") || strings.ContainsAny(key, "\\\x00\r\n") {
20 return nil, ErrSignature
21 }
22 for _, part := range parts {
23 if part == "" || part == "." || part == ".." {
24 return nil, ErrSignature
25 }
26 }
27 out := append([]byte("carlos-host-stop-v1\x00"+key+"\x00"), body...)
28 return out, nil
29}
30func Verify(pub ed25519.PublicKey, key string, body, signature []byte) error {
31 wire, err := message(key, body)
32 if err != nil || len(pub) != ed25519.PublicKeySize || len(signature) != ed25519.SignatureSize || !ed25519.Verify(pub, wire, signature) {
33 return ErrSignature
34 }
35 return nil
36}
37func immutable(ctx context.Context, s release.Store, key string, body []byte) error {
38 if _, err := s.Put(ctx, key, body, ""); err == nil {
39 return nil
40 } else if !errors.Is(err, release.ErrCASConflict) {
41 return err
42 }
43 existing, _, err := s.Get(ctx, key)
44 if err != nil {
45 return err
46 }
47 if !bytes.Equal(existing, body) {
48 return ErrSignature
49 }
50 return nil
51}
52func Publish(ctx context.Context, s release.Store, private ed25519.PrivateKey, key string, body []byte) error {
53 wire, err := message(key, body)
54 if err != nil || s == nil || len(private) != ed25519.PrivateKeySize {
55 return ErrSignature
56 }
57 signature := ed25519.Sign(private, wire)
58 if err = immutable(ctx, s, key, body); err != nil {
59 return err
60 }
61 return immutable(ctx, s, key+".sig", signature)
62}
63