1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package app
17
18 import (
19 "bytes"
20 "context"
21 "encoding/base64"
22 "encoding/json"
23 "errors"
24 "fmt"
25 "strconv"
26 "time"
27
28 "github.com/go-openapi/runtime"
29 "github.com/spf13/cobra"
30 "github.com/spf13/viper"
31
32 "github.com/sigstore/rekor/cmd/rekor-cli/app/format"
33 "github.com/sigstore/rekor/pkg/client"
34 "github.com/sigstore/rekor/pkg/generated/client/entries"
35 "github.com/sigstore/rekor/pkg/generated/models"
36 "github.com/sigstore/rekor/pkg/log"
37 "github.com/sigstore/rekor/pkg/sharding"
38 "github.com/sigstore/rekor/pkg/tle"
39 "github.com/sigstore/rekor/pkg/types"
40 "github.com/sigstore/rekor/pkg/verify"
41 )
42
43 type getCmdOutput struct {
44 Attestation string
45 AttestationType string
46 Body interface{}
47 LogIndex int
48 IntegratedTime int64
49 UUID string
50 LogID string
51 }
52
53 func (g *getCmdOutput) String() string {
54 s := fmt.Sprintf("LogID: %v\n", g.LogID)
55
56 if g.Attestation != "" {
57 s += fmt.Sprintf("Attestation: %s\n", g.Attestation)
58 }
59
60 s += fmt.Sprintf("Index: %d\n", g.LogIndex)
61 dt := time.Unix(g.IntegratedTime, 0).UTC().Format(time.RFC3339)
62 s += fmt.Sprintf("IntegratedTime: %s\n", dt)
63 s += fmt.Sprintf("UUID: %s\n", g.UUID)
64 var b bytes.Buffer
65 e := json.NewEncoder(&b)
66 e.SetIndent("", " ")
67 _ = e.Encode(g.Body)
68 s += fmt.Sprintf("Body: %s\n", b.Bytes())
69 return s
70 }
71
72
73 var getCmd = &cobra.Command{
74 Use: "get",
75 Short: "Rekor get command",
76 Long: `Get information regarding entries in the transparency log`,
77 PreRun: func(cmd *cobra.Command, _ []string) {
78
79 if err := viper.BindPFlags(cmd.Flags()); err != nil {
80 log.CliLogger.Fatalf("Error initializing cmd line args: %w", err)
81 }
82 },
83 Run: format.WrapCmd(func(_ []string) (interface{}, error) {
84 ctx := context.Background()
85 rekorClient, err := client.GetRekorClient(viper.GetString("rekor_server"), client.WithUserAgent(UserAgent()), client.WithRetryCount(viper.GetUint("retry")), client.WithLogger(log.CliLogger))
86 if err != nil {
87 return nil, err
88 }
89
90 logIndex := viper.GetString("log-index")
91 uuid := viper.GetString("uuid")
92 if logIndex == "" && uuid == "" {
93 return nil, errors.New("either --uuid or --log-index must be specified")
94 }
95
96 verifier, err := loadVerifier(rekorClient)
97 if err != nil {
98 return nil, fmt.Errorf("retrieving rekor public key")
99 }
100
101 if logIndex != "" {
102 params := entries.NewGetLogEntryByIndexParams()
103 params.SetTimeout(viper.GetDuration("timeout"))
104 logIndexInt, err := strconv.ParseInt(logIndex, 10, 0)
105 if err != nil {
106 return nil, fmt.Errorf("error parsing --log-index: %w", err)
107 }
108 params.LogIndex = logIndexInt
109
110 resp, err := rekorClient.Entries.GetLogEntryByIndex(params)
111 if err != nil {
112 return nil, err
113 }
114 var e models.LogEntryAnon
115 for ix, entry := range resp.Payload {
116
117 e = entry
118 if err := verify.VerifyLogEntry(ctx, &e, verifier); err != nil {
119 return nil, fmt.Errorf("unable to verify entry was added to log: %w", err)
120 }
121
122
123 if entry.Verification.InclusionProof.Checkpoint != nil {
124 if err := verify.VerifyCheckpointSignature(&e, verifier); err != nil {
125 return nil, err
126 }
127 }
128
129 return parseEntry(ix, entry)
130 }
131 }
132
133
134 if uuid != "" {
135 params := entries.NewGetLogEntryByUUIDParams()
136 params.SetTimeout(viper.GetDuration("timeout"))
137 params.EntryUUID = uuid
138
139 resp, err := rekorClient.Entries.GetLogEntryByUUID(params)
140 if err != nil {
141 return nil, err
142 }
143
144 var e models.LogEntryAnon
145 for k, entry := range resp.Payload {
146 if err := compareEntryUUIDs(params.EntryUUID, k); err != nil {
147 return nil, err
148 }
149
150
151 e = entry
152 if err := verify.VerifyLogEntry(ctx, &e, verifier); err != nil {
153 return nil, fmt.Errorf("unable to verify entry was added to log: %w", err)
154 }
155
156 return parseEntry(k, entry)
157 }
158 }
159
160 return nil, errors.New("entry not found")
161 }),
162 }
163
164
165
166 func compareEntryUUIDs(requestEntryUUID string, responseEntryUUID string) error {
167 requestUUID, err := sharding.GetUUIDFromIDString(requestEntryUUID)
168 if err != nil {
169 return err
170 }
171 responseUUID, err := sharding.GetUUIDFromIDString(responseEntryUUID)
172 if err != nil {
173 return err
174 }
175
176 if requestUUID != responseUUID {
177 return fmt.Errorf("unexpected entry returned from rekor server: expected %s, got %s", requestEntryUUID, responseEntryUUID)
178 }
179
180 requestTreeID, err := sharding.GetTreeIDFromIDString(requestEntryUUID)
181 if err != nil {
182 if errors.Is(err, sharding.ErrPlainUUID) {
183
184 return nil
185 }
186
187 return err
188 }
189
190 responseTreeID, err := sharding.GetTreeIDFromIDString(responseEntryUUID)
191 if err != nil {
192 if errors.Is(err, sharding.ErrPlainUUID) {
193
194
195 return nil
196 }
197 return err
198 }
199
200 if requestTreeID != responseTreeID {
201 return fmt.Errorf("unexpected entry returned from rekor server: expected %s, got %s", requestEntryUUID, responseEntryUUID)
202 }
203 return nil
204 }
205
206 func parseEntry(uuid string, e models.LogEntryAnon) (interface{}, error) {
207 if viper.GetString("format") == "tle" {
208 return tle.GenerateTransparencyLogEntry(e)
209 }
210
211 b, err := base64.StdEncoding.DecodeString(e.Body.(string))
212 if err != nil {
213 return nil, err
214 }
215
216 pe, err := models.UnmarshalProposedEntry(bytes.NewReader(b), runtime.JSONConsumer())
217 if err != nil {
218 return nil, err
219 }
220 eimpl, err := types.UnmarshalEntry(pe)
221 if err != nil {
222 return nil, err
223 }
224
225 obj := getCmdOutput{
226 Body: eimpl,
227 UUID: uuid,
228 IntegratedTime: *e.IntegratedTime,
229 LogIndex: int(*e.LogIndex),
230 LogID: *e.LogID,
231 }
232
233 if e.Attestation != nil {
234 obj.Attestation = string(e.Attestation.Data)
235 }
236
237 return &obj, nil
238 }
239
240 func init() {
241 initializePFlagMap()
242 if err := addUUIDPFlags(getCmd, false); err != nil {
243 log.CliLogger.Fatal("Error parsing cmd line args: ", err)
244 }
245 if err := addLogIndexFlag(getCmd, false); err != nil {
246 log.CliLogger.Fatal("Error parsing cmd line args: ", err)
247 }
248
249 rootCmd.AddCommand(getCmd)
250 }
251
View as plain text