-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP: Bring up to date with -09 draft
Signed-off-by: Ionut Mihalcea <ionut.mihalcea@arm.com>
- Loading branch information
Showing
8 changed files
with
1,039 additions
and
893 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,223 +1,73 @@ | ||
// Copyright 2023 Contributors to the Veraison project. | ||
// Copyright 2024 Contributors to the Veraison project. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package cmw | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/fxamacker/cbor/v2" | ||
) | ||
|
||
type Serialization uint | ||
|
||
const ( | ||
UnknownSerialization = Serialization(iota) | ||
JSONArray | ||
CBORArray | ||
CBORTag | ||
JSON | ||
CBOR | ||
) | ||
|
||
// a CMW object holds the internal representation of a RATS conceptual message | ||
// wrapper | ||
type CMW struct { | ||
typ Type | ||
val Value | ||
ind Indicator | ||
serialization Serialization | ||
} | ||
|
||
func (o *CMW) SetMediaType(v string) { _ = o.typ.Set(v) } | ||
func (o *CMW) SetContentFormat(v uint16) { _ = o.typ.Set(v) } | ||
func (o *CMW) SetTagNumber(v uint64) { _ = o.typ.Set(v) } | ||
func (o *CMW) SetValue(v []byte) { _ = o.val.Set(v) } | ||
func (o *CMW) SetIndicators(indicators ...Indicator) { | ||
var v Indicator | ||
|
||
for _, ind := range indicators { | ||
v.Set(ind) | ||
} | ||
|
||
o.ind = v | ||
val any | ||
} | ||
func (o *CMW) SetSerialization(s Serialization) { o.serialization = s } | ||
|
||
func (o CMW) GetValue() []byte { return o.val } | ||
func (o CMW) GetType() string { return o.typ.String() } | ||
func (o CMW) GetIndicator() Indicator { return o.ind } | ||
func (o CMW) GetSerialization() Serialization { return o.serialization } | ||
|
||
// Deserialize a CMW | ||
func (o *CMW) Deserialize(b []byte) error { | ||
s := sniff(b) | ||
|
||
o.serialization = s | ||
|
||
switch s { | ||
case JSONArray: | ||
return o.UnmarshalJSON(b) | ||
case CBORArray, CBORTag: | ||
return o.UnmarshalCBOR(b) | ||
} | ||
|
||
return errors.New("unknown CMW format") | ||
} | ||
|
||
// Serialize a CMW according to its provided Serialization | ||
func (o CMW) Serialize() ([]byte, error) { | ||
s := o.serialization | ||
switch s { | ||
case JSONArray: | ||
return o.MarshalJSON() | ||
case CBORArray, CBORTag: | ||
return o.MarshalCBOR() | ||
} | ||
return nil, fmt.Errorf("invalid serialization format %d", s) | ||
} | ||
|
||
func (o CMW) MarshalJSON() ([]byte, error) { return arrayEncode(json.Marshal, &o) } | ||
|
||
func (o CMW) MarshalCBOR() ([]byte, error) { | ||
s := o.serialization | ||
switch s { | ||
case CBORArray: | ||
return arrayEncode(cbor.Marshal, &o) | ||
case CBORTag: | ||
return o.encodeCBORTag() | ||
} | ||
return nil, fmt.Errorf("invalid serialization format: want CBORArray or CBORTag, got %d", s) | ||
} | ||
|
||
func (o CMW) encodeCBORTag() ([]byte, error) { | ||
var ( | ||
tag cbor.RawTag | ||
err error | ||
) | ||
|
||
if !o.typ.IsSet() || !o.val.IsSet() { | ||
return nil, fmt.Errorf("type and value MUST be set in CMW") | ||
} | ||
|
||
tag.Number, err = o.typ.TagNumber() | ||
if err != nil { | ||
return nil, fmt.Errorf("getting a suitable tag value: %w", err) | ||
} | ||
|
||
tag.Content, err = cbor.Marshal(o.val) | ||
if err != nil { | ||
return nil, fmt.Errorf("marshaling tag value: %w", err) | ||
} | ||
|
||
return tag.MarshalCBOR() | ||
} | ||
|
||
func (o *CMW) UnmarshalCBOR(b []byte) error { | ||
if arrayDecode[cbor.RawMessage](cbor.Unmarshal, b, o) == nil { | ||
o.serialization = CBORArray | ||
switch sniff(b) { | ||
case collection: | ||
var coll Collection | ||
if err := coll.Deserialize(b); err != nil { | ||
return err | ||
} | ||
o.val = coll | ||
return nil | ||
} | ||
|
||
if o.decodeCBORTag(b) == nil { | ||
// the serialization attribute is set by decodeCBORTag | ||
case leaf: | ||
var lf Leaf | ||
lf.Deserialize(b) | ||
o.val = lf | ||
return nil | ||
default: | ||
return errors.New("unknown CMW type") | ||
} | ||
|
||
return errors.New("invalid CBOR-encoded CMW") | ||
} | ||
|
||
func (o *CMW) UnmarshalJSON(b []byte) error { | ||
err := arrayDecode[json.RawMessage](json.Unmarshal, b, o) | ||
o.serialization = JSONArray | ||
return err | ||
} | ||
|
||
func (o *CMW) decodeCBORTag(b []byte) error { | ||
var ( | ||
v cbor.RawTag | ||
m []byte | ||
err error | ||
) | ||
|
||
if err = v.UnmarshalCBOR(b); err != nil { | ||
return fmt.Errorf("unmarshal CMW CBOR Tag: %w", err) | ||
} | ||
|
||
if err = cbor.Unmarshal(v.Content, &m); err != nil { | ||
return fmt.Errorf("unmarshal CMW CBOR Tag bstr-wrapped value: %w", err) | ||
func (o CMW) Serialize(s Serialization) ([]byte, error) { | ||
switch v := o.val.(type) { | ||
case Leaf: | ||
return v.Serialize(s) | ||
case Collection: | ||
return v.Serialize(s) | ||
default: | ||
return nil, fmt.Errorf("unsupported type %T", v) | ||
} | ||
|
||
_ = o.typ.Set(v.Number) | ||
_ = o.val.Set(m) | ||
o.serialization = CBORTag | ||
|
||
return nil | ||
} | ||
|
||
func sniff(b []byte) Serialization { | ||
if len(b) == 0 { | ||
return UnknownSerialization | ||
} | ||
|
||
if b[0] == 0x82 || b[0] == 0x83 { | ||
return CBORArray | ||
} else if b[0] >= 0xc0 && b[0] <= 0xdb { | ||
return CBORTag | ||
} else if b[0] == 0x5b { | ||
return JSONArray | ||
} | ||
|
||
return UnknownSerialization | ||
} | ||
type cmwNodeType uint | ||
|
||
type ( | ||
arrayDecoder func([]byte, any) error | ||
arrayEncoder func(any) ([]byte, error) | ||
const ( | ||
unknownType = cmwNodeType(iota) | ||
leaf | ||
collection | ||
) | ||
|
||
func arrayDecode[V json.RawMessage | cbor.RawMessage]( | ||
dec arrayDecoder, b []byte, o *CMW, | ||
) error { | ||
var a []V | ||
func sniff(b []byte) cmwNodeType { | ||
s := sniff_leaf(b) | ||
|
||
if err := dec(b, &a); err != nil { | ||
return err | ||
} | ||
|
||
alen := len(a) | ||
|
||
if alen < 2 || alen > 3 { | ||
return fmt.Errorf("wrong number of entries (%d) in the CMW array", alen) | ||
} | ||
|
||
if err := dec(a[0], &o.typ); err != nil { | ||
return fmt.Errorf("unmarshaling type: %w", err) | ||
} | ||
|
||
if err := dec(a[1], &o.val); err != nil { | ||
return fmt.Errorf("unmarshaling value: %w", err) | ||
} | ||
|
||
if alen == 3 { | ||
if err := dec(a[2], &o.ind); err != nil { | ||
return fmt.Errorf("unmarshaling indicator: %w", err) | ||
if s == UnknownForm { | ||
if sniff_collection(b) { | ||
return collection | ||
} | ||
} else { | ||
return leaf | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func arrayEncode(enc arrayEncoder, o *CMW) ([]byte, error) { | ||
if !o.typ.IsSet() || !o.val.IsSet() { | ||
return nil, fmt.Errorf("type and value MUST be set in CMW") | ||
} | ||
|
||
a := []any{o.typ, o.val} | ||
|
||
if !o.ind.Empty() { | ||
a = append(a, o.ind) | ||
} | ||
|
||
return enc(a) | ||
return unknownType | ||
} |
Oops, something went wrong.