--- CBOR-XS/XS.pm 2016/04/25 18:20:22 1.53 +++ CBOR-XS/XS.pm 2016/11/25 12:16:12 1.63 @@ -66,7 +66,7 @@ use common::sense; -our $VERSION = 1.41; +our $VERSION = 1.51; our @ISA = qw(Exporter); our @EXPORT = qw(encode_cbor decode_cbor); @@ -182,7 +182,7 @@ This means that such values will only be encoded once, and will not result in a deep cloning of the value on decode, in decoders supporting the value sharing extension. This also makes it possible to encode cyclic data -structures (which need C to ne enabled to be decoded by this +structures (which need C to be enabled to be decoded by this module). It is recommended to leave it off unless you know your @@ -442,7 +442,7 @@ subsequent calls to C or C start to parse a new CBOR value from the beginning of the C<$buffer> again. -This method can be caled at any time, but it I be called if you want +This method can be called at any time, but it I be called if you want to change your C<$buffer> or there was a decoding error and you want to reuse the C<$cbor> object for future incremental parsings. @@ -929,16 +929,25 @@ C method encodes "small" bigints into normal CBOR integers, and others into positive/negative CBOR bignums. -=item 4, 5 (decimal fraction/bigfloat) +=item 4, 5, 264, 265 (decimal fraction/bigfloat) Both decimal fractions and bigfloats are decoded into L objects. The corresponding C method I -encodes into a decimal fraction. +encodes into a decimal fraction (either tag 4 or 264). -CBOR cannot represent bigfloats with I large exponents - conversion -of such big float objects is undefined. +NaN and infinities are not encoded properly, as they cannot be represented +in CBOR. -Also, NaN and infinities are not encoded properly. +See L for more info. + +=item 30 (rational numbers) + +These tags are decoded into L objects. The corresponding +C method encodes rational numbers with denominator +C<1> via their numerator only, i.e., they become normal integers or +C. + +See L for more info. =item 21, 22, 23 (expected later JSON conversion) @@ -978,7 +987,12 @@ any buffer overflows. Obviously, this module should ensure that and I am trying hard on making that true, but you never know. -Second, you need to avoid resource-starving attacks. That means you should +Second, CBOR::XS supports object serialisation - decoding CBOR can cause +calls to I C method in I package that exists in your +process (that is, CBOR::XS will not try to load modules, but any existing +C method or function can be called, so they all have to be secure). + +Third, you need to avoid resource-starving attacks. That means you should limit the size of CBOR data you accept, or make sure then when your resources run out, that's just fine (e.g. by using a separate process that can crash safely). The size of a CBOR string in octets is usually a good @@ -987,7 +1001,7 @@ too late when you already have it in memory, so you might want to check the size before you accept the string. -Third, CBOR::XS recurses using the C stack when decoding objects and +Fourth, CBOR::XS recurses using the C stack when decoding objects and arrays. The C stack is a limited resource: for instance, on my amd64 machine with 8MB of stack size I can decode around 180k nested arrays but only 14k nested CBOR objects (due to perl itself recursing deeply on croak @@ -1004,6 +1018,39 @@ information you might want to make sure that exceptions thrown by CBOR::XS will not end up in front of untrusted eyes. + +=head1 BIGNUM SECURITY CONSIDERATIONS + +CBOR::XS provides a C method for both L and +L that tries to encode the number in the simplest possible +way, that is, either a CBOR integer, a CBOR bigint/decimal fraction (tag +4) or an arbitrary-exponent decimal fraction (tag 264). Rational numbers +(L, tag 30) can also contain bignums as members. + +CBOR::XS will also understand base-2 bigfloat or arbitrary-exponent +bigfloats (tags 5 and 265), but it will never generate these on its own. + +Using the built-in L support, encoding and decoding +decimal fractions is generally fast. Decoding bigints can be slow for very +big numbers (tens of thousands of digits, something that could potentially +be caught by limiting the size of CBOR texts), and decoding bigfloats or +arbitrary-exponent bigfloats can be I slow (minutes, decades) +for large exponents (roughly 40 bit and longer). + +Additionally, L can take advantage of other bignum +libraries, such as L, which cannot handle big floats with large +exponents, and might simply abort or crash your program, due to their code +quality. + +This can be a concern if you want to parse untrusted CBOR. If it is, you +might want to disable decoding of tag 2 (bigint) and 3 (negative bigint) +types. You should also disable types 5 and 265, as these can be slow even +without bigints. + +Disabling bigints will also partially or fully disable types that rely on +them, e.g. rational numbers that use bignums. + + =head1 CBOR IMPLEMENTATION NOTES This section contains some random implementation notes. They do not @@ -1098,11 +1145,26 @@ Math::BigFloat->new ($_[1][1] . "E" . $_[1][0]) }, + 264 => sub { # decimal fraction with arbitrary exponent + require Math::BigFloat; + Math::BigFloat->new ($_[1][1] . "E" . $_[1][0]) + }, + 5 => sub { # bigfloat, array require Math::BigFloat; scalar Math::BigFloat->new ($_[1][1]) * Math::BigFloat->new (2)->bpow ($_[1][0]) }, + 265 => sub { # bigfloat with arbitrary exponent + require Math::BigFloat; + scalar Math::BigFloat->new ($_[1][1]) * Math::BigFloat->new (2)->bpow ($_[1][0]) + }, + + 30 => sub { # rational number + require Math::BigRat; + Math::BigRat->new ("$_[1][0]/$_[1][1]") # separate parameters only work in recent versons + }, + 21 => sub { pop }, # expected conversion to base64url encoding 22 => sub { pop }, # expected conversion to base64 encoding 23 => sub { pop }, # expected conversion to base16 encoding @@ -1131,7 +1193,7 @@ } sub Math::BigInt::TO_CBOR { - if ($_[0] >= -2147483648 && $_[0] <= 2147483647) { + if (-2147483648 <= $_[0] && $_[0] <= 2147483647) { $_[0]->numify } else { my $hex = substr $_[0]->as_hex, 2; @@ -1142,7 +1204,20 @@ sub Math::BigFloat::TO_CBOR { my ($m, $e) = $_[0]->parts; - tag 4, [$e->numify, $m] + + -9223372036854775808 <= $e && $e <= 18446744073709551615 + ? tag 4, [$e->numify, $m] + : tag 264, [$e, $m] +} + +sub Math::BigRat::TO_CBOR { + my ($n, $d) = $_[0]->parts; + + # older versions of BigRat need *1, as they not always return numbers + + $d*1 == 1 + ? $n*1 + : tag 30, [$n*1, $d*1] } sub Time::Piece::TO_CBOR {