Skip to content

Commit

Permalink
Merge pull request #1 from veraison/initial
Browse files Browse the repository at this point in the history
an initial implementation of CMW
  • Loading branch information
thomas-fossati authored Apr 18, 2023
2 parents f0a18c6 + 0c1e60f commit 589b768
Show file tree
Hide file tree
Showing 20 changed files with 1,414 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/ci-go-cover.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: cover ≥88%
on: [push, pull_request]
jobs:
cover:
name: Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.19"
- name: Checkout code
uses: actions/checkout@v2
- name: Go Coverage
run: |
go version
go test -short -cover | grep -o "coverage:.*of statements$" | python scripts/cov.py
shell: bash
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: ci
on: [push, pull_request]
jobs:
tests:
name: Test on ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.19"
- name: Checkout code
uses: actions/checkout@v2
- name: Run tests
run: |
go version
go test -v
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# RATS Conceptual Message Wrappers

[![cover ≥88%](https://github.com/veraison/cmw/actions/workflows/ci-go-cover.yml/badge.svg)](https://github.com/veraison/cmw/actions/workflows/ci-go-cover.yml)

Package `cmw` is a golang implementation of [draft-ftbs-rats-msg-wrap](https://datatracker.ietf.org/doc/draft-ftbs-rats-msg-wrap/).
128 changes: 128 additions & 0 deletions cfmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// auto-generated (see utils/README.md)
package cmw

var mt2cf = map[string]uint16{
`application/cbor`: 11060,
`image/png`: 23,
`application/multipart-core`: 62,
`application/cose-key-set`: 102,
`application/sensml+cbor`: 113,
`application/aif+cbor`: 290,
`application/yang-data+cbor`: 340,
`application/pkcs7-mime; smime-type=certs-only`: 281,
`application/pkcs10`: 286,
`application/td+json`: 432,
`application/json`: 11050,
`application/dots+cbor`: 271,
`application/pkcs7-mime; smime-type=server-generated-key`: 280,
`application/pkcs8`: 284,
`application/pkix-cert`: 287,
`application/link-format`: 40,
`application/aif+json`: 291,
`application/vnd.ocf+cbor`: 10000,
`text/plain; charset=utf-8`: 0,
`application/senml+xml`: 310,
`application/cose; cose-type="cose-sign1"`: 18,
`application/json-patch+json`: 51,
`application/tm+json`: 433,
`application/octet-stream`: 42,
`application/merge-patch+json`: 52,
`application/sensml+xml`: 311,
`application/vnd.oma.lwm2m+cbor`: 11544,
`application/cose; cose-type="cose-encrypt0"`: 16,
`application/exi`: 47,
`application/cose; cose-type="cose-encrypt"`: 96,
`application/coap-group+json`: 256,
`application/cose; cose-type="cose-sign"`: 98,
`application/cose-key`: 101,
`application/senml+cbor`: 112,
`application/senml-etch+json`: 320,
`image/jpeg`: 22,
`application/sensml+json`: 111,
`application/vnd.oma.lwm2m+tlv`: 11542,
`application/cose; cose-type="cose-mac0"`: 17,
`application/ace+cbor`: 19,
`application/senml-exi`: 114,
`application/swid+cbor`: 258,
`application/missing-blocks+cbor-seq`: 272,
`application/senml-etch+cbor`: 322,
`application/cbor-seq`: 63,
`application/senml+json`: 110,
`application/javascript`: 10002,
`image/svg+xml`: 30000,
`text/css`: 20000,
`application/xml`: 41,
`application/cose; cose-type="cose-mac"`: 97,
`application/sensml-exi`: 115,
`application/yang-data+cbor; id=sid`: 140,
`application/csrattrs`: 285,
`application/vnd.oma.lwm2m+json`: 11543,
`image/gif`: 21,
`application/cwt`: 61,
`application/concise-problem-details+cbor`: 257,
`application/yang-data+cbor; id=name`: 341,
`application/oscore`: 10001,
}

var cf2mt = map[uint16]string{
11060: `application/cbor`,
23: `image/png`,
62: `application/multipart-core`,
102: `application/cose-key-set`,
113: `application/sensml+cbor`,
290: `application/aif+cbor`,
340: `application/yang-data+cbor`,
281: `application/pkcs7-mime; smime-type=certs-only`,
286: `application/pkcs10`,
432: `application/td+json`,
284: `application/pkcs8`,
287: `application/pkix-cert`,
11050: `application/json`,
271: `application/dots+cbor`,
280: `application/pkcs7-mime; smime-type=server-generated-key`,
40: `application/link-format`,
291: `application/aif+json`,
10000: `application/vnd.ocf+cbor`,
0: `text/plain; charset=utf-8`,
310: `application/senml+xml`,
18: `application/cose; cose-type="cose-sign1"`,
51: `application/json-patch+json`,
433: `application/tm+json`,
11544: `application/vnd.oma.lwm2m+cbor`,
42: `application/octet-stream`,
52: `application/merge-patch+json`,
311: `application/sensml+xml`,
256: `application/coap-group+json`,
16: `application/cose; cose-type="cose-encrypt0"`,
47: `application/exi`,
96: `application/cose; cose-type="cose-encrypt"`,
320: `application/senml-etch+json`,
98: `application/cose; cose-type="cose-sign"`,
101: `application/cose-key`,
112: `application/senml+cbor`,
22: `image/jpeg`,
111: `application/sensml+json`,
258: `application/swid+cbor`,
272: `application/missing-blocks+cbor-seq`,
322: `application/senml-etch+cbor`,
11542: `application/vnd.oma.lwm2m+tlv`,
17: `application/cose; cose-type="cose-mac0"`,
19: `application/ace+cbor`,
114: `application/senml-exi`,
30000: `image/svg+xml`,
63: `application/cbor-seq`,
110: `application/senml+json`,
10002: `application/javascript`,
140: `application/yang-data+cbor; id=sid`,
285: `application/csrattrs`,
11543: `application/vnd.oma.lwm2m+json`,
20000: `text/css`,
41: `application/xml`,
97: `application/cose; cose-type="cose-mac"`,
115: `application/sensml-exi`,
341: `application/yang-data+cbor; id=name`,
10001: `application/oscore`,
21: `image/gif`,
61: `application/cwt`,
257: `application/concise-problem-details+cbor`,
}
195 changes: 195 additions & 0 deletions cmw.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// Copyright 2023 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 (
JSONArray = Serialization(iota)
CBORArray
CBORTag
Unknown
)

// a CMW object holds the internal representation of a RATS conceptual message
// wrapper
type CMW struct {
typ Type
val Value
ind Indicator
}

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
}

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 }

// Deserialize a CMW
func (o *CMW) Deserialize(b []byte) error {
switch sniff(b) {
case JSONArray:
return o.UnmarshalJSON(b)
case CBORArray:
return o.UnmarshalCBOR(b)
case CBORTag:
return o.UnmarshalCBORTag(b)
}
return errors.New("unknown CMW format")
}

// Serialize a CMW according to the provided Serialization
func (o CMW) Serialize(s Serialization) ([]byte, error) {
switch s {
case JSONArray:
return o.MarshalJSON()
case CBORArray:
return o.MarshalCBOR()
case CBORTag:
return o.MarshalCBORTag()
}
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) { return arrayEncode(cbor.Marshal, &o) }

func (o CMW) MarshalCBORTag() ([]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 {
return arrayDecode[cbor.RawMessage](cbor.Unmarshal, b, o)
}

func (o *CMW) UnmarshalJSON(b []byte) error {
return arrayDecode[json.RawMessage](json.Unmarshal, b, o)
}

func (o *CMW) UnmarshalCBORTag(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)
}

_ = o.typ.Set(v.Number)
_ = o.val.Set(m)

return nil
}

func sniff(b []byte) Serialization {
if len(b) == 0 {
return Unknown
}

if b[0] == 0x82 || b[0] == 0x83 {
return CBORArray
} else if b[0] >= 0xc0 && b[0] <= 0xdf {
return CBORTag
} else if b[0] == 0x5b {
return JSONArray
}

return Unknown
}

type (
arrayDecoder func([]byte, interface{}) error
arrayEncoder func(interface{}) ([]byte, error)
)

func arrayDecode[V json.RawMessage | cbor.RawMessage](
dec arrayDecoder, b []byte, o *CMW,
) error {
var a []V

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)
}
}

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 := []interface{}{o.typ, o.val}

if !o.ind.Empty() {
a = append(a, o.ind)
}

return enc(a)
}
Loading

0 comments on commit 589b768

Please sign in to comment.