Merge pull request #14174 from thaJeztah/bump_cbor

vendor: github.com/fxamacker/cbor/v2 v2.9.4
This commit is contained in:
Samuel Karp authored and GitHub committed 2026-09-16 20:58:52 +00:00
commit fe4ef048ad
9 files changed
+241 -89

No files matched your search

+1 -1
View File
@@ -108,7 +108,7 @@ require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/felixge/httpsnoop v1.1.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.1 // indirect
github.com/fxamacker/cbor/v2 v2.9.4 // indirect
github.com/go-jose/go-jose/v4 v4.1.5 // indirect
github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
+2 -2
View File
@@ -106,8 +106,8 @@ github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeO
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ=
github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo=
github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA=
github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+14 -12
View File
@@ -683,7 +683,7 @@ because RFC 8949 treats CBOR data item with remaining bytes as malformed.
Other useful functions:
- `Diagnose`, `DiagnoseFirst` produce human-readable [Extended Diagnostic Notation](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G) from CBOR data.
- `UnmarshalFirst` decodes first CBOR data item and return any remaining bytes.
- `Wellformed` returns true if the CBOR data item is well-formed.
- `Wellformed` returns nil error if the CBOR data item is well-formed.
Interfaces identical or comparable to Go `encoding` packages include:
`Marshaler`, `Unmarshaler`, `BinaryMarshaler`, and `BinaryUnmarshaler`.
@@ -702,27 +702,29 @@ Default limits may need to be increased for systems handling very large data (e.
## Status
v2.9.1 (Mar 29-30, 2026) includes important bugfixes, defensive checks, improved code quality, and more tests. Although not public, the fuzzer was also improved by adding more fuzz tests.
v2.9.2 (Sunday, May 3, 2026) refactors and hardens the streaming encoder by adding stricter checks for encoding to CBOR indefinite-length data. This prevents improper use of this library from producing malformed CBOR indefinite-length data that would be rejected by the decoder.
v2.9.1 passed fuzz tests and is production quality.
This release includes other bugfixes, defensive checks, and added more tests.
The minimum version of Go required to build:
- v2.8.0 and newer releases require go 1.20+.
- v2.7.1 and older releases require go 1.17+.
v2.9.2 passed fuzz tests (billions of executions) and is production quality.
For more details, see [v2.9.1 release notes](https://github.com/fxamacker/cbor/releases).
For more details, see [v2.9.2 release notes](https://github.com/fxamacker/cbor/releases).
### Prior Releases
[v2.9.0](https://github.com/fxamacker/cbor/releases/tag/v2.9.0) (Jul 13, 2025) improved interoperability/transcoding between CBOR & JSON, refactored tests, and improved docs. It passed fuzz tests (billions of executions) and is production quality.
Releases and commits tend to be on Sundays because my work schedule didn't leave time to work on this during weekdays (sometimes consecutive weekends and consecutive Christmas breaks, too). Monday morning releases were to allow more fuzzing to run overnight before clicking the release button.
[v2.8.0](https://github.com/fxamacker/cbor/releases/tag/v2.8.0) (March 30, 2025) is a small release primarily to add `omitzero` option to struct field tags and fix bugs. It passed fuzz tests (billions of executions) and is production quality.
[v2.9.1](https://github.com/fxamacker/cbor/releases/tag/v2.9.1) (Monday, Mar 30, 2026) includes important bugfixes, defensive checks, improved code quality, and more tests. Although not public, the fuzzer was also improved by adding more fuzz tests. It passed fuzz tests (billions of executions) and is production quality.
[v2.7.0](https://github.com/fxamacker/cbor/releases/tag/v2.7.0) (June 23, 2024) adds features and improvements that help large projects (e.g. Kubernetes) use CBOR as an alternative to JSON and Protocol Buffers. Other improvements include speedups, improved memory use, bug fixes, new serialization options, etc. It passed fuzz tests (5+ billion executions) and is production quality.
[v2.9.0](https://github.com/fxamacker/cbor/releases/tag/v2.9.0) (Sunday, Jul 13, 2025) improved interoperability/transcoding between CBOR & JSON, refactored tests, and improved docs. It passed fuzz tests (billions of executions) and is production quality.
[v2.6.0](https://github.com/fxamacker/cbor/releases/tag/v2.6.0) (February 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings.
[v2.8.0](https://github.com/fxamacker/cbor/releases/tag/v2.8.0) (Sunday, March 30, 2025) is a small release primarily to add `omitzero` option to struct field tags and fix bugs. It passed fuzz tests (billions of executions) and is production quality.
[v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) was released on Sunday, August 13, 2023 with new features and important bug fixes. It is fuzz tested and production quality after extended beta [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023).
[v2.7.0](https://github.com/fxamacker/cbor/releases/tag/v2.7.0) (Monday, June 23, 2024) adds features and improvements that help large projects (e.g. Kubernetes) use CBOR as an alternative to JSON and Protocol Buffers. Other improvements include speedups, improved memory use, bug fixes, new serialization options, etc. It passed fuzz tests (5+ billion executions) and is production quality.
[v2.6.0](https://github.com/fxamacker/cbor/releases/tag/v2.6.0) (Sunday, Feb 11, 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings.
[v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Sunday, August 13, 2023) adds new features and important bug fixes. It is fuzz tested and production quality after extended beta [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023).
__IMPORTANT__: 👉 Before upgrading from v2.4 or older release, please read the notable changes highlighted in the release notes. v2.5.0 is a large release with bug fixes to error handling for extraneous data in `Unmarshal`, etc. that should be reviewed before upgrading.
+27 -7
View File
@@ -41,13 +41,14 @@ const (
)
type typeInfo struct {
elemTypeInfo *typeInfo
keyTypeInfo *typeInfo
typ reflect.Type
kind reflect.Kind
nonPtrType reflect.Type
nonPtrKind reflect.Kind
spclType specialType
elemTypeInfo *typeInfo
keyTypeInfo *typeInfo
typ reflect.Type
kind reflect.Kind
nonPtrType reflect.Type
nonPtrKind reflect.Kind
spclType specialType
keyNeedsHashableValueCheck bool
}
func newTypeInfo(t reflect.Type) *typeInfo {
@@ -85,12 +86,31 @@ func newTypeInfo(t reflect.Type) *typeInfo {
tInfo.elemTypeInfo = getTypeInfo(t.Elem())
case reflect.Map:
tInfo.keyTypeInfo = getTypeInfo(t.Key())
tInfo.keyNeedsHashableValueCheck = needsHashableValueCheck(t.Key())
tInfo.elemTypeInfo = getTypeInfo(t.Elem())
}
return &tInfo
}
// needsHashableValueCheck returns true if the hashability of a value of
// the given type can't be determined by the static type.
func needsHashableValueCheck(typ reflect.Type) bool {
switch typ.Kind() {
case reflect.Interface:
return true
case reflect.Array:
return needsHashableValueCheck(typ.Elem())
case reflect.Struct:
for i := 0; i < typ.NumField(); i++ {
if needsHashableValueCheck(typ.Field(i).Type) {
return true
}
}
}
return false
}
type decodingStructType struct {
fields decodingFields
fieldIndicesByName map[string]int // Only populated if toArray is false
+45 -19
View File
@@ -1769,6 +1769,7 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
}
return t, true, nil
}
d.skip()
return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()}
case cborTypeTextString:
@@ -1845,6 +1846,7 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
return time.Unix(int64(seconds), int64(fractional*1e9)), true, nil
default:
d.skip()
return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()}
}
}
@@ -2263,7 +2265,7 @@ func (d *decoder) applyByteStringTextConversion(
default:
// If this happens, there is a bug: the decoder has pushed an invalid
// "expected later encoding" tag to the stack.
panic(fmt.Sprintf("unrecognized expected later encoding tag: %d", d.expectedLaterEncodingTags))
panic(fmt.Sprintf("unrecognized expected later encoding tag: %d", d.expectedLaterEncodingTags[len(d.expectedLaterEncodingTags)-1]))
}
case reflect.Slice:
@@ -2486,7 +2488,6 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
keyType, eleType := tInfo.keyTypeInfo.typ, tInfo.elemTypeInfo.typ
reuseKey, reuseEle := isImmutableKind(tInfo.keyTypeInfo.kind), isImmutableKind(tInfo.elemTypeInfo.kind)
var keyValue, eleValue reflect.Value
keyIsInterfaceType := keyType == typeIntf // If key type is interface{}, need to check if key value is hashable.
var err, lastErr error
keyCount := v.Len()
var existingKeys map[any]bool // Store existing map keys, used for detecting duplicate map key.
@@ -2515,22 +2516,28 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
}
// Detect if CBOR map key can be used as Go map key.
if keyIsInterfaceType && keyValue.Elem().IsValid() {
if !isHashableValue(keyValue.Elem()) {
var converted bool
if d.dm.mapKeyByteString == MapKeyByteStringAllowed {
var k any
k, converted = convertByteSliceToByteString(keyValue.Elem().Interface())
if converted {
keyValue.Set(reflect.ValueOf(k))
if tInfo.keyNeedsHashableValueCheck {
containedKeyValue := keyValue
if keyValue.Kind() == reflect.Interface {
containedKeyValue = keyValue.Elem()
}
if containedKeyValue.IsValid() {
if !isHashableValue(containedKeyValue) {
var converted bool
if d.dm.mapKeyByteString == MapKeyByteStringAllowed {
var k any
k, converted = convertByteSliceToByteString(containedKeyValue.Interface())
if converted {
keyValue.Set(reflect.ValueOf(k))
}
}
}
if !converted {
if err == nil {
err = &InvalidMapKeyTypeError{keyValue.Elem().Type().String()}
if !converted {
if err == nil {
err = &InvalidMapKeyTypeError{containedKeyValue.Type().String()}
}
d.skip()
continue
}
d.skip()
continue
}
}
}
@@ -3044,7 +3051,6 @@ func (d *decoder) nextCBORNil() bool {
type jsonUnmarshaler interface{ UnmarshalJSON([]byte) error }
var (
typeIntf = reflect.TypeOf([]any(nil)).Elem()
typeTime = reflect.TypeOf(time.Time{})
typeBigInt = reflect.TypeOf(big.Int{})
typeUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
@@ -3265,15 +3271,35 @@ func isHashableValue(rv reflect.Value) bool {
case reflect.Slice, reflect.Map, reflect.Func:
return false
case reflect.Struct:
switch rv.Type() {
case reflect.Struct, reflect.Interface:
switch rt := rv.Type(); rt {
case typeTag:
tag := rv.Interface().(Tag)
return isHashableValue(reflect.ValueOf(tag.Content))
case typeTime:
return true
case typeBigInt:
return false
default:
// Both Type.Comparable() and Value.Comparable() checks are needed.
// - Type.Comparable() returns true for interface types, so
// Value.Comparable() is needed to check the dynamic value.
// - Value.Comparable() returns true for zero-length array of interface,
// array, or struct type (as of go1.27.1), so Type.Comparable() is
// needed to reject zero-length array of uncomparable type.
return rt.Comparable() && rv.Comparable()
}
case reflect.Array:
switch rt := rv.Type(); rt.Elem().Kind() {
case reflect.Slice, reflect.Map, reflect.Func:
return false
case reflect.Struct, reflect.Array, reflect.Interface:
return rt.Comparable() && rv.Comparable()
}
}
return true
}
+15 -5
View File
@@ -56,20 +56,30 @@ modes won't accidentally change at runtime after they're created.
Modes are intended to be reused and are safe for concurrent use.
EncMode and DecMode Interfaces
EncMode, UserBufferEncMode, and DecMode Interfaces
// EncMode interface uses immutable options and is safe for concurrent use.
type EncMode interface {
Marshal(v interface{}) ([]byte, error)
Marshal(v any) ([]byte, error)
NewEncoder(w io.Writer) *Encoder
EncOptions() EncOptions // returns copy of options
EncOptions() EncOptions
}
// UserBufferEncMode extends EncMode with MarshalToBuffer, which supports
// user specified buffer rather than encoding into the built-in buffer pool.
type UserBufferEncMode interface {
EncMode
MarshalToBuffer(v any, buf *bytes.Buffer) error
}
// DecMode interface uses immutable options and is safe for concurrent use.
type DecMode interface {
Unmarshal(data []byte, v interface{}) error
Unmarshal(data []byte, v any) error
UnmarshalFirst(data []byte, v any) (rest []byte, err error)
Valid(data []byte) error // Deprecated: use Wellformed instead.
Wellformed(data []byte) error
NewDecoder(r io.Reader) *Decoder
DecOptions() DecOptions // returns copy of options
DecOptions() DecOptions
}
Using Default Encoding Mode
+131 -42
View File
@@ -6,6 +6,7 @@ package cbor
import (
"bytes"
"errors"
"fmt"
"io"
"reflect"
)
@@ -157,11 +158,32 @@ func (dec *Decoder) overwriteBuf(newBuf []byte) {
dec.off = 0
}
// indefDataItem tracks open indefinite-length data item during encoding.
// typ is the CBOR type of the indefinite-length data item.
// count is the number of items written so far.
// For indefinite-length maps, count must be even (key/value pairs) when
// the container is closed.
type indefDataItem struct {
typ cborType
count int
}
// IndefiniteLengthMapOddItemCountError indicates that EndIndefinite was
// called on an open indefinite-length map with an odd number of items.
type IndefiniteLengthMapOddItemCountError struct {
count int
}
func (e *IndefiniteLengthMapOddItemCountError) Error() string {
return fmt.Sprintf("cbor: cannot end indefinite-length map with %d item(s)", e.count)
}
// Encoder writes CBOR values to io.Writer.
type Encoder struct {
w io.Writer
em *encMode
indefTypes []cborType
w io.Writer
em *encMode
indefs []indefDataItem
scratch [1]byte // reused for single-byte writes (indefinite-length head and break code)
}
// NewEncoder returns a new encoder that writes to w using the default encoding options.
@@ -171,37 +193,40 @@ func NewEncoder(w io.Writer) *Encoder {
// Encode writes the CBOR encoding of v.
func (enc *Encoder) Encode(v any) error {
if len(enc.indefTypes) > 0 {
switch enc.indefTypes[len(enc.indefTypes)-1] {
case cborTypeTextString:
if v == nil {
return errors.New("cbor: cannot encode nil for indefinite-length text string")
}
k := reflect.TypeOf(v).Kind()
if k != reflect.String {
return errors.New("cbor: cannot encode item type " + k.String() + " for indefinite-length text string")
}
case cborTypeByteString:
if v == nil {
return errors.New("cbor: cannot encode nil for indefinite-length byte string")
}
t := reflect.TypeOf(v)
k := t.Kind()
if (k != reflect.Array && k != reflect.Slice) || t.Elem().Kind() != reflect.Uint8 {
return errors.New("cbor: cannot encode item type " + k.String() + " for indefinite-length byte string")
}
if len(enc.indefs) > 0 {
err := validateIndefiniteLengthChunkByType(enc.indefs[len(enc.indefs)-1].typ, v)
if err != nil {
return err
}
}
buf := getEncodeBuffer()
err := encode(buf, enc.em, reflect.ValueOf(v))
// Validate the encoded chunk against the indefinite-length data item using a byte-based check.
// This reliably detects chunks from cbor.Marshaler, registered tags, StringToByteString, etc.,
// which may produce a chunk inconsistent with the parent's major type.
// Applies only to indefinite-length byte/text string parents (RFC 8949 Section 3.2.3).
if err == nil && len(enc.indefs) > 0 {
err = validateIndefiniteLengthChunkByData(enc.indefs[len(enc.indefs)-1].typ, buf.Bytes(), v)
}
if err == nil {
_, err = enc.w.Write(buf.Bytes())
}
putEncodeBuffer(buf)
return err
if err != nil {
return err
}
if len(enc.indefs) > 0 {
enc.indefs[len(enc.indefs)-1].count++
}
return nil
}
// StartIndefiniteByteString starts indefinite-length byte string encoding.
@@ -233,37 +258,101 @@ func (enc *Encoder) StartIndefiniteMap() error {
}
// EndIndefinite closes last opened indefinite-length value.
// It returns *IndefiniteLengthMapOddItemCountError without writing the
// "break" code if the open indefinite-length map has an odd number of
// items; the encoder state is unchanged so the caller can write the
// missing value and retry.
func (enc *Encoder) EndIndefinite() error {
if len(enc.indefTypes) == 0 {
if len(enc.indefs) == 0 {
return errors.New("cbor: cannot encode \"break\" code outside indefinite length values")
}
_, err := enc.w.Write([]byte{cborBreakFlag})
if err == nil {
enc.indefTypes = enc.indefTypes[:len(enc.indefTypes)-1]
// Verify that indefinite-length map has even number of elements
top := enc.indefs[len(enc.indefs)-1]
if top.typ == cborTypeMap && top.count%2 != 0 {
return &IndefiniteLengthMapOddItemCountError{count: top.count}
}
return err
// Write break code
enc.scratch[0] = cborBreakFlag
_, err := enc.w.Write(enc.scratch[:])
if err != nil {
return err
}
enc.indefs = enc.indefs[:len(enc.indefs)-1]
// Increment parent container's item count because the child
// (indefinite-length data item) is fully written to the stream.
if len(enc.indefs) > 0 {
enc.indefs[len(enc.indefs)-1].count++
}
return nil
}
func (enc *Encoder) startIndefinite(typ cborType) error {
if enc.em.indefLength == IndefLengthForbidden {
return &IndefiniteLengthError{typ}
}
var head byte
switch typ {
case cborTypeByteString:
head = cborByteStringWithIndefiniteLengthHead
case cborTypeTextString:
head = cborTextStringWithIndefiniteLengthHead
case cborTypeArray:
head = cborArrayWithIndefiniteLengthHead
case cborTypeMap:
head = cborMapWithIndefiniteLengthHead
// Verify that new indefinite-length data item is not a chunk in indefinite-length byte/text string.
if len(enc.indefs) > 0 {
parent := enc.indefs[len(enc.indefs)-1].typ
if parent == cborTypeByteString || parent == cborTypeTextString {
return errors.New("cbor: cannot encode indefinite-length " + typ.String() +
" as chunk of indefinite-length " + parent.String())
}
}
_, err := enc.w.Write([]byte{head})
if err == nil {
enc.indefTypes = append(enc.indefTypes, typ)
// Write indefinite-length head.
enc.scratch[0] = byte(typ) | additionalInformationAsIndefiniteLengthFlag
_, err := enc.w.Write(enc.scratch[:])
if err != nil {
return err
}
return err
enc.indefs = append(enc.indefs, indefDataItem{typ: typ})
return nil
}
// validateIndefiniteLengthChunkByType rejects chunks based solely on their Go type.
func validateIndefiniteLengthChunkByType(indefiniteLengthCborType cborType, v any) error {
if indefiniteLengthCborType != cborTypeByteString &&
indefiniteLengthCborType != cborTypeTextString {
return nil
}
if v == nil {
return errors.New("cbor: cannot encode nil for indefinite-length " + indefiniteLengthCborType.String())
}
return nil
}
// validateIndefiniteLengthChunkByData checks that chunk is a definite-length
// CBOR data item with a matching major type.
// No-op for indefinite-length array/map, where any data item is valid.
func validateIndefiniteLengthChunkByData(indefiniteLengthCborType cborType, chunk []byte, v any) error {
if indefiniteLengthCborType != cborTypeByteString &&
indefiniteLengthCborType != cborTypeTextString {
return nil
}
if len(chunk) == 0 {
return errors.New("cbor: cannot encode item type " + reflect.TypeOf(v).Kind().String() +
" for indefinite-length " + indefiniteLengthCborType.String())
}
t, ai := parseInitialByte(chunk[0])
if t != indefiniteLengthCborType {
return errors.New("cbor: cannot encode item type " + reflect.TypeOf(v).Kind().String() +
" for indefinite-length " + indefiniteLengthCborType.String())
}
if ai == additionalInformationAsIndefiniteLengthFlag {
return errors.New("cbor: cannot encode indefinite-length " + indefiniteLengthCborType.String() +
" as chunk of indefinite-length " + indefiniteLengthCborType.String())
}
return nil
}
// RawMessage is a raw encoded CBOR value.
+5
View File
@@ -155,6 +155,7 @@ type TagSet interface {
Add(opts TagOptions, contentType reflect.Type, num uint64, nestedNum ...uint64) error
// Remove removes given tag content type from TagSet.
// Remove is a no-op if contentType is nil.
Remove(contentType reflect.Type)
tagProvider
@@ -245,7 +246,11 @@ func (t *syncTagSet) Add(opts TagOptions, contentType reflect.Type, num uint64,
}
// Remove removes given tag content type from TagSet.
// Remove is a no-op if contentType is nil.
func (t *syncTagSet) Remove(contentType reflect.Type) {
if contentType == nil {
return
}
for contentType.Kind() == reflect.Pointer {
contentType = contentType.Elem()
}
+1 -1
View File
@@ -353,7 +353,7 @@ github.com/felixge/httpsnoop
## explicit; go 1.23
github.com/fsnotify/fsnotify
github.com/fsnotify/fsnotify/internal
# github.com/fxamacker/cbor/v2 v2.9.1
# github.com/fxamacker/cbor/v2 v2.9.4
## explicit; go 1.20
github.com/fxamacker/cbor/v2
# github.com/go-jose/go-jose/v4 v4.1.5