Skip to content

Commit

Permalink
CLI, "corim display" subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
thomas-fossati committed Oct 7, 2021
1 parent d63262b commit aefab11
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 42 deletions.
22 changes: 4 additions & 18 deletions cli/cmd/comidDisplay.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/veraison/corim/comid"
)

var (
Expand Down Expand Up @@ -47,7 +46,7 @@ func NewComidDisplayCmd() *cobra.Command {

errs := 0
for _, file := range filesList {
if err := displayComid(file); err != nil {
if err := displayComidFile(file); err != nil {
fmt.Printf("failed displaying %q: %v", file, err)
errs++
continue
Expand All @@ -72,31 +71,18 @@ func NewComidDisplayCmd() *cobra.Command {
return cmd
}

func displayComid(file string) error {
func displayComidFile(file string) error {
var (
data []byte
err error
c comid.Comid
)

if data, err = afero.ReadFile(fs, file); err != nil {
return fmt.Errorf("error loading CoMID from %s: %w", file, err)
}

if err = c.FromCBOR(data); err != nil {
return fmt.Errorf("error decoding CoMID from %s: %w", file, err)
}

prettyPrint := true
json, err := c.ToJSON(prettyPrint)
if err != nil {
return fmt.Errorf("error JSON encoding CoMID %s: %w", file, err)
}

fmt.Println("[ ", file, " ]")
fmt.Println(string(json))

return nil
// use file name as heading
return printComid(data, file)
}

func checkComidDisplayArgs() error {
Expand Down
18 changes: 0 additions & 18 deletions cli/cmd/comidDisplay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,6 @@ func Test_ComidDisplayCmd_file_with_invalid_cbor(t *testing.T) {
assert.EqualError(t, err, "1/1 display(s) failed")
}

func Test_ComidDisplayCmd_file_with_invalid_comid(t *testing.T) {
var err error

cmd := NewComidDisplayCmd()

fs = afero.NewMemMapFs()
err = afero.WriteFile(fs, "bad-comid.cbor", []byte{0xa0}, 0400)
require.NoError(t, err)

args := []string{
"--file=bad-comid.cbor",
}
cmd.SetArgs(args)

err = cmd.Execute()
assert.EqualError(t, err, "1/1 display(s) failed")
}

func Test_ComidDisplayCmd_file_with_valid_comid(t *testing.T) {
var err error

Expand Down
37 changes: 37 additions & 0 deletions cli/cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
package cmd

import (
"encoding/json"
"fmt"
"path/filepath"

"github.com/spf13/afero"
"github.com/veraison/corim/comid"
"github.com/veraison/swid"
)

func filesList(files, dirs []string, ext string) []string {
Expand All @@ -33,3 +37,36 @@ func filesList(files, dirs []string, ext string) []string {

return l
}

type FromCBORLoader interface {
FromCBOR([]byte) error
}

func printJSONFromCBOR(fcl FromCBORLoader, cbor []byte, heading string) error {
var (
err error
j []byte
)

if err = fcl.FromCBOR(cbor); err != nil {
return fmt.Errorf("CBOR decoding failed: %w", err)
}

indent := " "
if j, err = json.MarshalIndent(fcl, "", indent); err != nil {
return fmt.Errorf("JSON encoding failed: %w", err)
}

fmt.Println(heading)
fmt.Println(string(j))

return nil
}

func printComid(cbor []byte, heading string) error {
return printJSONFromCBOR(&comid.Comid{}, cbor, heading)
}

func printCoswid(cbor []byte, heading string) error {
return printJSONFromCBOR(&swid.SoftwareIdentity{}, cbor, heading)
}
136 changes: 136 additions & 0 deletions cli/cmd/corimDisplay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright 2021 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"bytes"
"encoding/json"
"errors"
"fmt"

"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/veraison/corim/corim"
)

var (
corimDisplayCorimFile *string
corimDisplayShowTags *bool
)

var corimDisplayCmd = NewCorimDisplayCmd()

func NewCorimDisplayCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "display",
Short: "display the content of a CoRIM as JSON",
Long: `display the content of a CoRIM as JSON
Display the contents of the signed CoRIM signed-corim.cbor
cli corim display --corim-file signed-corim.cbor
Display the contents of the signed CoRIM yet-another-signed-corim.cbor and
also unpack any embedded CoRIM and CoSWID
cli corim display --corim-file yet-another-signed-corim.cbor --show-tags
`,

RunE: func(cmd *cobra.Command, args []string) error {
if err := checkCorimDisplayArgs(); err != nil {
return err
}

if err := display(*corimDisplayCorimFile, *corimDisplayShowTags); err != nil {
return err
}

return nil
},
}

corimDisplayCorimFile = cmd.Flags().StringP("corim-file", "f", "", "a signed CoRIM file (in CBOR format)")
corimDisplayShowTags = cmd.Flags().BoolP("show-tags", "v", false, "display embedded tags")

return cmd
}

func checkCorimDisplayArgs() error {
if corimDisplayCorimFile == nil || *corimDisplayCorimFile == "" {
return errors.New("no CoRIM supplied")
}

return nil
}

func display(signedCorimFile string, showTags bool) error {
var (
signedCorimCBOR []byte
metaJSON []byte
corimJSON []byte
err error
s corim.SignedCorim
)

if signedCorimCBOR, err = afero.ReadFile(fs, signedCorimFile); err != nil {
return fmt.Errorf("error loading signed CoRIM from %s: %w", signedCorimFile, err)
}

if err = s.FromCOSE(signedCorimCBOR); err != nil {
return fmt.Errorf("error decoding signed CoRIM from %s: %w", signedCorimFile, err)
}

if metaJSON, err = json.MarshalIndent(&s.Meta, "", " "); err != nil {
return fmt.Errorf("error decoding CoRIM Meta from %s: %w", signedCorimFile, err)
}

fmt.Println("Meta:")
fmt.Println(string(metaJSON))

if corimJSON, err = json.MarshalIndent(&s.UnsignedCorim, "", " "); err != nil {
return fmt.Errorf("error decoding unsigned CoRIM from %s: %w", signedCorimFile, err)
}

fmt.Println("Corim:")
fmt.Println(string(corimJSON))

if showTags {
fmt.Println("Tags:")
for i, e := range s.UnsignedCorim.Tags {
var (
coswidTag = []byte{0xd9, 0x01, 0xf9} // 505()
comidTag = []byte{0xd9, 0x01, 0xfa} // 506()
)

// need at least 3 bytes for the tag and 1 for the smallest bstr
if len(e) < len(comidTag)+1 {
fmt.Printf(">> skipping malformed tag at index %d\n", i)
continue
}

// split tag from data
cborTag, cborData := e[:3], e[3:]

hdr := fmt.Sprintf(">> [ %d ]", i)

if bytes.Equal(cborTag, comidTag) {
if err = printComid(cborData, hdr); err != nil {
fmt.Printf(">> skipping malformed CoMID tag at index %d: %v\n", i, err)
}
} else if bytes.Equal(cborTag, coswidTag) {
if err = printCoswid(cborData, hdr); err != nil {
fmt.Printf(">> skipping malformed CoSWID tag at index %d: %v\n", i, err)
}
} else {
fmt.Printf("unmatched CBOR tag: %x\n", e[:2])
}
}
}

return nil
}

func init() {
corimCmd.AddCommand(corimDisplayCmd)
}
113 changes: 113 additions & 0 deletions cli/cmd/corimDisplay_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2021 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"testing"

"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_CorimDisplayCmd_unknown_argument(t *testing.T) {
cmd := NewCorimDisplayCmd()

args := []string{"--unknown-argument=val"}
cmd.SetArgs(args)

err := cmd.Execute()
assert.EqualError(t, err, "unknown flag: --unknown-argument")
}

func Test_CorimDisplayCmd_mandatory_args_missing_corim_file(t *testing.T) {
cmd := NewCorimDisplayCmd()

args := []string{
"--show-tags",
}
cmd.SetArgs(args)

err := cmd.Execute()
assert.EqualError(t, err, "no CoRIM supplied")
}

func Test_CorimDisplayCmd_non_existent_corim_file(t *testing.T) {
cmd := NewCorimDisplayCmd()

args := []string{
"--corim-file=nonexistent.cbor",
}
cmd.SetArgs(args)

fs = afero.NewMemMapFs()

err := cmd.Execute()
assert.EqualError(t, err, "error loading signed CoRIM from nonexistent.cbor: open nonexistent.cbor: file does not exist")
}

func Test_CorimDisplayCmd_bad_signed_corim(t *testing.T) {
cmd := NewCorimDisplayCmd()

args := []string{
"--corim-file=bad.txt",
}
cmd.SetArgs(args)

fs = afero.NewMemMapFs()
err := afero.WriteFile(fs, "bad.txt", []byte("hello!"), 0644)
require.NoError(t, err)

err = cmd.Execute()
assert.EqualError(t, err, "error decoding signed CoRIM from bad.txt: failed CBOR decoding for COSE-Sign1 signed CoRIM: unexpected EOF")
}

func Test_CorimDisplayCmd_invalid_signed_corim(t *testing.T) {
cmd := NewCorimDisplayCmd()

args := []string{
"--corim-file=invalid.cbor",
}
cmd.SetArgs(args)

fs = afero.NewMemMapFs()
err := afero.WriteFile(fs, "invalid.cbor", testSignedCorimInvalid, 0644)
require.NoError(t, err)

err = cmd.Execute()
assert.EqualError(t, err, "error decoding signed CoRIM from invalid.cbor: failed validation of unsigned CoRIM: empty id")
}

func Test_CorimDisplayCmd_ok_top_level_view(t *testing.T) {
cmd := NewCorimDisplayCmd()

args := []string{
"--corim-file=ok.cbor",
}
cmd.SetArgs(args)

fs = afero.NewMemMapFs()
err := afero.WriteFile(fs, "ok.cbor", testSignedCorimValid, 0644)
require.NoError(t, err)

err = cmd.Execute()
assert.NoError(t, err)
}

func Test_CorimDisplayCmd_ok_nested_view(t *testing.T) {
cmd := NewCorimDisplayCmd()

args := []string{
"--corim-file=ok.cbor",
"--show-tags",
}
cmd.SetArgs(args)

fs = afero.NewMemMapFs()
err := afero.WriteFile(fs, "ok.cbor", testSignedCorimValid, 0644)
require.NoError(t, err)

err = cmd.Execute()
assert.NoError(t, err)
}
2 changes: 1 addition & 1 deletion cli/cmd/corimVerify.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func NewCorimVerifyCmd() *cobra.Command {
},
}

corimVerifyCorimFile = cmd.Flags().StringP("corim-file", "f", "", "an signed CoRIM file (in CBOR format)")
corimVerifyCorimFile = cmd.Flags().StringP("corim-file", "f", "", "a signed CoRIM file (in CBOR format)")
corimVerifyKeyFile = cmd.Flags().StringP("key-file", "k", "", "verification key in JWK format")

return cmd
Expand Down
3 changes: 2 additions & 1 deletion cli/cmd/test_vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ var (
"kid": "1"
}`)

testSignedCorimValid = comid.MustHexDecode(nil, "d284585da3012603746170706c69636174696f6e2f72696d2b63626f72085841a200a2007441434d45204c7464207369676e696e67206b657901d8207468747470733a2f2f61636d652e6578616d706c6501a200c11a61ce480001c11a69546780a059061aa600505c57e8f446cd421b91c908cf93e13cfc0183590216d901faa40065656e2d474201a10050366d0a0a598845ed84882f2a544f62420281a3006941434d45204c74642e01d8207468747470733a2f2f61636d652e6578616d706c65028300010204a1028282a200a300d90227582061636d652d696d706c656d656e746174696f6e2d69642d303030303030303031016441434d45026a526f616452756e6e657201d90226582101ceebae7b8927a3227e5303cf5e0f1f7b34bb542ad7250ac03fbcde36ec2f150881a100787c4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a30444151634451674145466e3074616f41775233506d724b6b594c74417344396f30354b534d366d6267664e436770754c306736567054486b5a6c3733776b354244786f56376e2b4f656565306949716b5733484d5a54334554696e694a64673d3d82a200a300d90227582061636d652d696d706c656d656e746174696f6e2d69642d303030303030303031016441434d45026a526f616452756e6e657201d902265821014ca3e4f50bf248c39787020d68ffd05c88767751bf2645ca923f57a98becd29681a100787c4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741453656777165376879334f385970612b425545544c556a424e5533724558565579743958485237484a574c473758544b51643969316b565258654250444c466e66597275312f657578526e4a4d374839556f46444c64413d3d5901a3d901faa40065656e2d474201a1005043bbe37f2e614b33aed353cff1428b160281a3006941434d45204c74642e01d8207468747470733a2f2f61636d652e6578616d706c65028300010204a1008182a100a300d90227582061636d652d696d706c656d656e746174696f6e2d69642d303030303030303031016441434d45026a526f616452756e6e657283a200d90258a30162424c0465322e312e30055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b01a102818201582087428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7a200d90258a3016450526f540465312e332e35055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b01a10281820158200263829989b6fd954f72baaf2fc64bc2e2f01d692d4de72986ea808f6e99813fa200d90258a3016441526f540465302e312e34055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b01a1028182015820a3a5e715f0cc574a73c3f9bebb6bc24f32ffd5b67b387244c2c909da779a147859017cd901f9a8007820636f6d2e61636d652e727264323031332d63652d7370312d76342d312d352d300c0001783041434d4520526f616472756e6e6572204465746563746f72203230313320436f796f74652045646974696f6e205350310d65342e312e3505a5182b65747269616c182d6432303133182f66636f796f7465183473526f616472756e6e6572204465746563746f721836637370310282a3181f745468652041434d4520436f72706f726174696f6e18206861636d652e636f6d1821820102a3181f75436f796f74652053657276696365732c20496e632e18206c6d79636f796f74652e636f6d18210404a21826781c7777772e676e752e6f72672f6c6963656e7365732f67706c2e7478741828676c6963656e736506a110a318186a72726465746563746f7218196d2570726f6772616d6461746125181aa111a318186e72726465746563746f722e657865141a000820e80782015820a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a0281a200d820784068747470733a2f2f706172656e742e6578616d706c652f72696d732f63636233616138352d363162342d343066312d383438652d3032616436653861323534620182015820e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d750382482b06010401a02064781c687474703a2f2f61726d2e636f6d2f696f742f70726f66696c652f3104a200c11a61ce480001c11a695467800581a3006941434d45204c74642e01d8206c61636d652e6578616d706c6502810158400d35302dda8e1249e295154255370fade855043ae59c7d460b49415fddec40d70e22f21f98ac18bc69a18d175730f6d7c6c28fa0819aeded8653f69d71d60172")
testSignedCorimValid = comid.MustHexDecode(nil, "d284585da3012603746170706c69636174696f6e2f72696d2b63626f72085841a200a2007441434d45204c7464207369676e696e67206b657901d8207468747470733a2f2f61636d652e6578616d706c6501a200c11a61ce480001c11a69546780a059061aa600505c57e8f446cd421b91c908cf93e13cfc0183590216d901faa40065656e2d474201a10050366d0a0a598845ed84882f2a544f62420281a3006941434d45204c74642e01d8207468747470733a2f2f61636d652e6578616d706c65028300010204a1028282a200a300d90227582061636d652d696d706c656d656e746174696f6e2d69642d303030303030303031016441434d45026a526f616452756e6e657201d90226582101ceebae7b8927a3227e5303cf5e0f1f7b34bb542ad7250ac03fbcde36ec2f150881a100787c4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a30444151634451674145466e3074616f41775233506d724b6b594c74417344396f30354b534d366d6267664e436770754c306736567054486b5a6c3733776b354244786f56376e2b4f656565306949716b5733484d5a54334554696e694a64673d3d82a200a300d90227582061636d652d696d706c656d656e746174696f6e2d69642d303030303030303031016441434d45026a526f616452756e6e657201d902265821014ca3e4f50bf248c39787020d68ffd05c88767751bf2645ca923f57a98becd29681a100787c4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741453656777165376879334f385970612b425545544c556a424e5533724558565579743958485237484a574c473758544b51643969316b565258654250444c466e66597275312f657578526e4a4d374839556f46444c64413d3d5901a3d901faa40065656e2d474201a1005043bbe37f2e614b33aed353cff1428b160281a3006941434d45204c74642e01d8207468747470733a2f2f61636d652e6578616d706c65028300010204a1008182a100a300d90227582061636d652d696d706c656d656e746174696f6e2d69642d303030303030303031016441434d45026a526f616452756e6e657283a200d90258a30162424c0465322e312e30055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b01a102818201582087428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7a200d90258a3016450526f540465312e332e35055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b01a10281820158200263829989b6fd954f72baaf2fc64bc2e2f01d692d4de72986ea808f6e99813fa200d90258a3016441526f540465302e312e34055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b01a1028182015820a3a5e715f0cc574a73c3f9bebb6bc24f32ffd5b67b387244c2c909da779a147859017cd901f9a8007820636f6d2e61636d652e727264323031332d63652d7370312d76342d312d352d300c0001783041434d4520526f616472756e6e6572204465746563746f72203230313320436f796f74652045646974696f6e205350310d65342e312e3505a5182b65747269616c182d6432303133182f66636f796f7465183473526f616472756e6e6572204465746563746f721836637370310282a3181f745468652041434d4520436f72706f726174696f6e18206861636d652e636f6d1821820102a3181f75436f796f74652053657276696365732c20496e632e18206c6d79636f796f74652e636f6d18210404a21826781c7777772e676e752e6f72672f6c6963656e7365732f67706c2e7478741828676c6963656e736506a110a318186a72726465746563746f7218196d2570726f6772616d6461746125181aa111a318186e72726465746563746f722e657865141a000820e80782015820a314fc2dc663ae7a6b6bc6787594057396e6b3f569cd50fd5ddb4d1bbafd2b6a0281a200d820784068747470733a2f2f706172656e742e6578616d706c652f72696d732f63636233616138352d363162342d343066312d383438652d3032616436653861323534620182015820e45b72f5c0c0b572db4d8d3ab7e97f368ff74e62347a824decb67a84e5224d750382482b06010401a02064781c687474703a2f2f61726d2e636f6d2f696f742f70726f66696c652f3104a200c11a61ce480001c11a695467800581a3006941434d45204c74642e01d8206c61636d652e6578616d706c6502810158400d35302dda8e1249e295154255370fade855043ae59c7d460b49415fddec40d70e22f21f98ac18bc69a18d175730f6d7c6c28fa0819aeded8653f69d71d60172")
testSignedCorimInvalid = comid.MustHexDecode(nil, "d284585da3012603746170706c69636174696f6e2f72696d2b63626f72085841a200a2007441434d45204c7464207369676e696e67206b657901d8207468747470733a2f2f61636d652e6578616d706c6501a200c11a61ce480001c11a69546780a041a044deadbeef")
)
Loading

0 comments on commit aefab11

Please sign in to comment.