Skip to content

Commit

Permalink
Prevent an inappropriate use of BinaryUnmarshaler
Browse files Browse the repository at this point in the history
Don't allow CBOR byte string (major type 2) as input to Go's
Time.UnmarshalBinary.

Time values should only be encoded/decoded using these
CBOR data types: pos or neg integer, float, and text string.

For more info, see RFC 7049 section 2.4.1.

Closes Issue #8.
  • Loading branch information
Faye Amacker committed Oct 23, 2019
1 parent f74f1d0 commit 34ffc3a
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 8 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

# fxamacker/cbor - CBOR library in Go

CBOR is a concise binary alternative to JSON, and is specified in RFC 7049.
CBOR is a concise binary alternative to JSON, and is specified in [RFC 7049](https://tools.ietf.org/html/rfc7049).

fxamacker/cbor is designed to be:
* __Easy__ -- idiomatic API like `encoding/json`.
* __Safe and reliable__ -- no `unsafe` pkg, coverage at 96%, and 10+ hrs of [fuzzing](https://github.com/fxamacker/cbor-fuzz) before each release.
* __Standards-compliant__ -- supports [CBOR](https://tools.ietf.org/html/rfc7049), including canonical CBOR encodings ([RFC 7049](https://tools.ietf.org/html/rfc7049#section-3.9) and [CTAP2](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#ctap2-canonical-cbor-encoding-form)).
* __Standards-compliant__ -- supports [CBOR](https://tools.ietf.org/html/rfc7049), including [canonical CBOR encodings](https://tools.ietf.org/html/rfc7049#section-3.9) (RFC 7049 and [CTAP2](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#ctap2-canonical-cbor-encoding-form)).
* __Small and self-contained__ -- compiles to under 0.5 MB and has no external dependencies.

fxamacker/cbor balances speed, safety, and compiled size. To keep size small, it avoids code generation. For safety, it avoids Go's `unsafe`. For speed, it uses safe optimizations: cache struct metadata, bypass `reflect` when appropriate, use `sync.Pool` to reuse transient objects, and etc.
Expand All @@ -21,7 +21,7 @@ fxamacker/cbor balances speed, safety, and compiled size. To keep size small, i

Version 1.x has:
* __Stable API__ -- won't make breaking API changes.
* __Stable requirements__ -- won't require newer than Go 1.12.
* __Stable requirements__ -- will always support Go v1.12.
* __Passed 30+ hrs of fuzzing__ -- v1.1.1 on linux_amd64 using prior corpus and [RFC 7049 tests](https://tools.ietf.org/html/rfc7049#appendix-A) as seed.

Oct 18, 2019: Released v1.1.1 to improve encoding speed: slice 50%, struct 30%, and map 14%.
Expand Down Expand Up @@ -57,7 +57,7 @@ Library sizes:

This library implements CBOR as specified in [RFC 7049](https://tools.ietf.org/html/rfc7049), with minor [limitations](#limitations).

It also supports canonical CBOR encodings (both [RFC 7049](https://tools.ietf.org/html/rfc7049#section-3.9) and [CTAP2](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#ctap2-canonical-cbor-encoding-form)). CTAP2 canonical CBOR encoding is used by [CTAP](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html) and [WebAuthn](https://www.w3.org/TR/webauthn/) in [FIDO2](https://fidoalliance.org/fido2/) framework.
It also supports [canonical CBOR encodings](https://tools.ietf.org/html/rfc7049#section-3.9) (both RFC 7049 and [CTAP2](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#ctap2-canonical-cbor-encoding-form)). CTAP2 canonical CBOR encoding is used by [CTAP](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html) and [WebAuthn](https://www.w3.org/TR/webauthn/) in [FIDO2](https://fidoalliance.org/fido2/) framework.

## Limitations

Expand Down
2 changes: 1 addition & 1 deletion decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ func fillFloat(t cborType, val float64, v reflect.Value) error {
}

func fillByteString(t cborType, val []byte, v reflect.Value) error {
if reflect.PtrTo(v.Type()).Implements(typeBinaryUnmarshaler) {
if v.Type() != typeTime && reflect.PtrTo(v.Type()).Implements(typeBinaryUnmarshaler) {
pv := reflect.New(v.Type())
pv.Elem().Set(v)
u := pv.Interface().(encoding.BinaryUnmarshaler)
Expand Down
11 changes: 8 additions & 3 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1276,19 +1276,19 @@ func TestDecodeTime(t *testing.T) {
wantTime: time.Time{},
},
{
name: "time without fractional seconds",
name: "time without fractional seconds", // positive integer
cborRFC3339Time: hexDecode("74323031332d30332d32315432303a30343a30305a"),
cborUnixTime: hexDecode("1a514b67b0"),
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00Z"),
},
{
name: "time with fractional seconds",
name: "time with fractional seconds", // float
cborRFC3339Time: hexDecode("76323031332d30332d32315432303a30343a30302e355a"),
cborUnixTime: hexDecode("fb41d452d9ec200000"),
wantTime: parseTime(time.RFC3339Nano, "2013-03-21T20:04:00.5Z"),
},
{
name: "time before January 1, 1970 UTC without fractional seconds",
name: "time before January 1, 1970 UTC without fractional seconds", // negative integer
cborRFC3339Time: hexDecode("74313936392d30332d32315432303a30343a30305a"),
cborUnixTime: hexDecode("3a0177f2cf"),
wantTime: parseTime(time.RFC3339Nano, "1969-03-21T20:04:00Z"),
Expand Down Expand Up @@ -1323,6 +1323,11 @@ func TestDecodeTimeError(t *testing.T) {
cborData: hexDecode("7f657374726561646d696e67ff"),
wantErrorMsg: "cbor: cannot set streaming for time.Time",
},
{
name: "byte string data cannot be decoded into time.Time",
cborData: hexDecode("4f013030303030303030e03031ed3030"),
wantErrorMsg: "cbor: cannot unmarshal byte string into Go value of type time.Time",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
Expand Down

0 comments on commit 34ffc3a

Please sign in to comment.