aboutsummaryrefslogtreecommitdiff
path: root/cmd/sigsum/cmd.go
blob: 7b9450a80b62742a5f5694d107e311f31e72cdf2 (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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package main

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"time"

	"git.sigsum.org/sigsum-go/pkg/requests"
	"git.sigsum.org/sigsum-go/pkg/types"
	"git.sigsum.org/sigsum-tools-go/pkg/client"
	"git.sigsum.org/sigsum-tools-go/pkg/policy"
	"git.sigsum.org/sigsum-tools-go/pkg/signatures"
	"git.sigsum.org/sigsum-tools-go/pkg/signatures/minisign"
	"git.sigsum.org/sigsum-tools-go/pkg/signatures/signify"
	"git.sigsum.org/sigsum-tools-go/pkg/signatures/ssh"
)

func cmdVerify(args []string, policy policy.Policy, optVerifyType, optVerifyKey string) error {
	return fmt.Errorf("TODO")
}

func cmdBundle(args []string, policy policy.Policy, optBundleType, optBundleKey, optBundleDomainHint string) error {
	if len(args) == 0 {
		return fmt.Errorf("bundle: need at least one file")
	}

	var parser signatures.Parser
	switch optBundleType {
	case "signify":
		parser = &signify.Parser{}
	case "minisign":
		parser = &minisign.Parser{}
	case "ssh":
		parser = &ssh.Parser{}
	default:
		return fmt.Errorf("bundle: invalid key type %q", optBundleType)
	}

	b, err := ioutil.ReadFile(optBundleKey)
	if err != nil {
		return fmt.Errorf("bundle: failed reading file %q: %v", optBundleKey, err)
	}
	pub, err := parser.PublicKey(bytes.NewBuffer(b))
	if err != nil {
		return fmt.Errorf("bundle: %v", err)
	}
	// TODO: check that domain hint is valid for public key

	var reqs []requests.Leaf
	for _, path := range args {
		preimage, err := fileHash(path)
		if err != nil {
			return fmt.Errorf("bundle: %v", err)
		}

		sigPath := path + parser.SignatureSuffix()
		b, err := ioutil.ReadFile(sigPath)
		if err != nil {
			return fmt.Errorf("bundle: failed reading file %q: %v", sigPath, err)
		}
		sig, err := parser.Signature(bytes.NewBuffer(b))
		if err != nil {
			return fmt.Errorf("bundle: %v", err)
		}

		req := requests.Leaf{
			ShardHint:       policy.ShardHint(),
			Preimage:        *preimage,
			Signature:       *sig,
			VerificationKey: *pub,
			DomainHint:      optBundleDomainHint,
		}

		sd := types.Statement{
			ShardHint: req.ShardHint,
			Checksum:  *types.HashFn(req.Preimage[:]),
		}
		if !sd.Verify(&req.VerificationKey, &req.Signature) {
			return fmt.Errorf("bundle: invalid signature for file %q", path)
		}
		reqs = append(reqs, req)
	}

	sc := client.NewSubmitClient(policy)
	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
	defer cancel()
	bundles, err := sc.AddLeaves(ctx, reqs)
	if err != nil {
		return fmt.Errorf("bundle: %v", err)
	}

	// TODO: verify bundles
	// TODO: write to files
	fmt.Printf("got %d bundles\n", len(bundles))
	return nil
}

func cmdFormat(args []string, policy policy.Policy) error {
	if len(args) != 1 {
		return fmt.Errorf("format: need exactly one file")
	}

	preimage, err := fileHash(args[0])
	if err != nil {
		return fmt.Errorf("format: %v", err)
	}
	sd := types.Statement{
		ShardHint: policy.ShardHint(),
		Checksum:  *types.HashFn(preimage[:]),
	}

	fmt.Printf("%s", sd.ToBinary())
	return nil
}

func cmdNamespace(args []string, policy policy.Policy) error {
	if len(args) != 0 {
		return fmt.Errorf("namespace: got trailing arguments")
	}

	fmt.Printf("tree_leaf:v0:%d@sigsum.org", policy.ShardHint())
	return nil
}

// TODO: don't read full file into memory at once
func fileHash(path string) (*types.Hash, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("failed reading file %q", path)
	}
	return types.HashFn(b), nil
}