From e684a3455bcc29a6e3e66a004e352dea4e1141e7 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 13 Feb 2019 15:05:36 +0100 Subject: BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922 Reviewed-by: Michael Brüning --- chromium/components/cbor/BUILD.gn | 26 +- chromium/components/cbor/cbor_constants.h | 37 - chromium/components/cbor/cbor_reader.cc | 404 ------- chromium/components/cbor/cbor_reader.h | 157 --- chromium/components/cbor/cbor_reader_fuzzer.cc | 30 - .../cbor/cbor_reader_fuzzer_corpus/cbor0 | Bin 1 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor1 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor10 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor11 | Bin 11 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor12 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor13 | Bin 11 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor14 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor15 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor16 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor17 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor18 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor19 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor2 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor20 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor21 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor22 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor23 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor24 | Bin 5 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor25 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor26 | Bin 9 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor27 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor28 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor29 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor3 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor30 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor31 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor32 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor33 | Bin 3 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor34 | Bin 5 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor35 | Bin 5 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor36 | Bin 5 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor37 | Bin 9 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor38 | Bin 9 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor39 | Bin 9 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor4 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor40 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor41 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor42 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor43 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor44 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor45 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor46 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor47 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor48 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor49 | Bin 10 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor5 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor50 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor51 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor52 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor53 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor54 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor55 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor56 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor57 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor58 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor59 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor6 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor60 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor61 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor62 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor63 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor64 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor65 | 2 - .../cbor/cbor_reader_fuzzer_corpus/cbor66 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor67 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor68 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor69 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor7 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor70 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor71 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor72 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor73 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor74 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor75 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor76 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor77 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor78 | 2 - .../cbor/cbor_reader_fuzzer_corpus/cbor79 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor8 | Bin 5 -> 0 bytes .../cbor/cbor_reader_fuzzer_corpus/cbor80 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor81 | 1 - .../cbor/cbor_reader_fuzzer_corpus/cbor9 | Bin 9 -> 0 bytes chromium/components/cbor/cbor_reader_unittest.cc | 1250 -------------------- chromium/components/cbor/cbor_values.cc | 283 ----- chromium/components/cbor/cbor_values.h | 191 --- chromium/components/cbor/cbor_values_unittest.cc | 372 ------ chromium/components/cbor/cbor_writer.cc | 180 --- chromium/components/cbor/cbor_writer.h | 100 -- chromium/components/cbor/cbor_writer_unittest.cc | 490 -------- chromium/components/cbor/constants.h | 37 + chromium/components/cbor/reader.cc | 400 +++++++ chromium/components/cbor/reader.h | 161 +++ chromium/components/cbor/reader_fuzzer.cc | 30 + .../components/cbor/reader_fuzzer_corpus/cbor0 | Bin 0 -> 1 bytes .../components/cbor/reader_fuzzer_corpus/cbor1 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor10 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor11 | Bin 0 -> 11 bytes .../components/cbor/reader_fuzzer_corpus/cbor12 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor13 | Bin 0 -> 11 bytes .../components/cbor/reader_fuzzer_corpus/cbor14 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor15 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor16 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor17 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor18 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor19 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor2 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor20 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor21 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor22 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor23 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor24 | Bin 0 -> 5 bytes .../components/cbor/reader_fuzzer_corpus/cbor25 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor26 | Bin 0 -> 9 bytes .../components/cbor/reader_fuzzer_corpus/cbor27 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor28 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor29 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor3 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor30 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor31 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor32 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor33 | Bin 0 -> 3 bytes .../components/cbor/reader_fuzzer_corpus/cbor34 | Bin 0 -> 5 bytes .../components/cbor/reader_fuzzer_corpus/cbor35 | Bin 0 -> 5 bytes .../components/cbor/reader_fuzzer_corpus/cbor36 | Bin 0 -> 5 bytes .../components/cbor/reader_fuzzer_corpus/cbor37 | Bin 0 -> 9 bytes .../components/cbor/reader_fuzzer_corpus/cbor38 | Bin 0 -> 9 bytes .../components/cbor/reader_fuzzer_corpus/cbor39 | Bin 0 -> 9 bytes .../components/cbor/reader_fuzzer_corpus/cbor4 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor40 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor41 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor42 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor43 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor44 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor45 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor46 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor47 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor48 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor49 | Bin 0 -> 10 bytes .../components/cbor/reader_fuzzer_corpus/cbor5 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor50 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor51 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor52 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor53 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor54 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor55 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor56 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor57 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor58 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor59 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor6 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor60 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor61 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor62 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor63 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor64 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor65 | 2 + .../components/cbor/reader_fuzzer_corpus/cbor66 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor67 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor68 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor69 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor7 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor70 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor71 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor72 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor73 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor74 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor75 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor76 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor77 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor78 | 2 + .../components/cbor/reader_fuzzer_corpus/cbor79 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor8 | Bin 0 -> 5 bytes .../components/cbor/reader_fuzzer_corpus/cbor80 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor81 | 1 + .../components/cbor/reader_fuzzer_corpus/cbor9 | Bin 0 -> 9 bytes chromium/components/cbor/reader_unittest.cc | 1236 +++++++++++++++++++ chromium/components/cbor/values.cc | 281 +++++ chromium/components/cbor/values.h | 190 +++ chromium/components/cbor/values_unittest.cc | 369 ++++++ chromium/components/cbor/writer.cc | 179 +++ chromium/components/cbor/writer.h | 100 ++ chromium/components/cbor/writer_unittest.cc | 489 ++++++++ 187 files changed, 3545 insertions(+), 3567 deletions(-) delete mode 100644 chromium/components/cbor/cbor_constants.h delete mode 100644 chromium/components/cbor/cbor_reader.cc delete mode 100644 chromium/components/cbor/cbor_reader.h delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer.cc delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor0 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor1 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor10 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor11 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor12 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor13 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor14 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor15 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor16 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor17 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor18 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor19 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor2 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor20 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor21 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor22 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor23 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor24 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor25 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor26 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor27 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor28 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor29 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor3 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor30 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor31 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor32 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor33 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor34 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor35 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor36 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor37 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor38 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor39 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor4 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor40 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor41 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor42 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor43 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor44 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor45 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor46 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor47 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor48 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor49 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor5 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor50 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor51 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor52 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor53 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor54 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor55 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor56 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor57 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor58 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor59 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor6 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor60 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor61 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor62 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor63 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor64 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor65 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor66 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor67 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor68 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor69 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor7 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor70 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor71 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor72 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor73 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor74 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor75 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor76 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor77 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor78 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor79 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor8 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor80 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor81 delete mode 100644 chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor9 delete mode 100644 chromium/components/cbor/cbor_reader_unittest.cc delete mode 100644 chromium/components/cbor/cbor_values.cc delete mode 100644 chromium/components/cbor/cbor_values.h delete mode 100644 chromium/components/cbor/cbor_values_unittest.cc delete mode 100644 chromium/components/cbor/cbor_writer.cc delete mode 100644 chromium/components/cbor/cbor_writer.h delete mode 100644 chromium/components/cbor/cbor_writer_unittest.cc create mode 100644 chromium/components/cbor/constants.h create mode 100644 chromium/components/cbor/reader.cc create mode 100644 chromium/components/cbor/reader.h create mode 100644 chromium/components/cbor/reader_fuzzer.cc create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor0 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor1 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor10 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor11 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor12 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor13 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor14 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor15 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor16 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor17 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor18 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor19 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor2 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor20 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor21 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor22 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor23 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor24 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor25 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor26 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor27 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor28 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor29 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor3 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor30 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor31 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor32 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor33 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor34 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor35 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor36 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor37 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor38 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor39 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor4 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor40 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor41 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor42 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor43 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor44 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor45 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor46 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor47 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor48 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor49 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor5 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor50 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor51 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor52 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor53 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor54 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor55 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor56 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor57 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor58 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor59 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor6 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor60 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor61 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor62 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor63 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor64 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor65 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor66 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor67 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor68 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor69 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor7 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor70 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor71 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor72 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor73 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor74 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor75 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor76 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor77 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor78 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor79 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor8 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor80 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor81 create mode 100644 chromium/components/cbor/reader_fuzzer_corpus/cbor9 create mode 100644 chromium/components/cbor/reader_unittest.cc create mode 100644 chromium/components/cbor/values.cc create mode 100644 chromium/components/cbor/values.h create mode 100644 chromium/components/cbor/values_unittest.cc create mode 100644 chromium/components/cbor/writer.cc create mode 100644 chromium/components/cbor/writer.h create mode 100644 chromium/components/cbor/writer_unittest.cc (limited to 'chromium/components/cbor') diff --git a/chromium/components/cbor/BUILD.gn b/chromium/components/cbor/BUILD.gn index c44e464409c..b0d8024539a 100644 --- a/chromium/components/cbor/BUILD.gn +++ b/chromium/components/cbor/BUILD.gn @@ -6,13 +6,13 @@ import("//testing/libfuzzer/fuzzer_test.gni") component("cbor") { sources = [ - "cbor_constants.h", - "cbor_reader.cc", - "cbor_reader.h", - "cbor_values.cc", - "cbor_values.h", - "cbor_writer.cc", - "cbor_writer.h", + "constants.h", + "reader.cc", + "reader.h", + "values.cc", + "values.h", + "writer.cc", + "writer.h", ] defines = [ "CBOR_IMPLEMENTATION" ] @@ -25,9 +25,9 @@ component("cbor") { source_set("unit_tests") { testonly = true sources = [ - "cbor_reader_unittest.cc", - "cbor_values_unittest.cc", - "cbor_writer_unittest.cc", + "reader_unittest.cc", + "values_unittest.cc", + "writer_unittest.cc", ] deps = [ @@ -38,14 +38,14 @@ source_set("unit_tests") { ] } -fuzzer_test("cbor_reader_fuzzer") { +fuzzer_test("reader_fuzzer") { sources = [ - "cbor_reader_fuzzer.cc", + "reader_fuzzer.cc", ] deps = [ ":cbor", "//base", ] - seed_corpus = "cbor_reader_fuzzer_corpus/" + seed_corpus = "reader_fuzzer_corpus/" libfuzzer_options = [ "max_len=65535" ] } diff --git a/chromium/components/cbor/cbor_constants.h b/chromium/components/cbor/cbor_constants.h deleted file mode 100644 index 69a6364c759..00000000000 --- a/chromium/components/cbor/cbor_constants.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_CBOR_CBOR_CONSTANTS_H_ -#define COMPONENTS_CBOR_CBOR_CONSTANTS_H_ - -#include - -namespace cbor { -namespace constants { - -// Mask selecting the low-order 5 bits of the "initial byte", which is where -// the additional information is encoded. -static constexpr uint8_t kAdditionalInformationMask = 0x1F; -// Mask selecting the high-order 3 bits of the "initial byte", which indicates -// the major type of the encoded value. -static constexpr uint8_t kMajorTypeMask = 0xE0; -// Indicates the number of bits the "initial byte" needs to be shifted to the -// right after applying |kMajorTypeMask| to produce the major type in the -// lowermost bits. -static constexpr uint8_t kMajorTypeBitShift = 5u; -// Indicates the integer is in the following byte. -static constexpr uint8_t kAdditionalInformation1Byte = 24u; -// Indicates the integer is in the next 2 bytes. -static constexpr uint8_t kAdditionalInformation2Bytes = 25u; -// Indicates the integer is in the next 4 bytes. -static constexpr uint8_t kAdditionalInformation4Bytes = 26u; -// Indicates the integer is in the next 8 bytes. -static constexpr uint8_t kAdditionalInformation8Bytes = 27u; - -extern const char kUnsupportedMajorType[]; - -} // namespace constants -} // namespace cbor - -#endif // COMPONENTS_CBOR_CBOR_CONSTANTS_H_ diff --git a/chromium/components/cbor/cbor_reader.cc b/chromium/components/cbor/cbor_reader.cc deleted file mode 100644 index e4efdae95bb..00000000000 --- a/chromium/components/cbor/cbor_reader.cc +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/cbor/cbor_reader.h" - -#include - -#include - -#include "base/numerics/checked_math.h" -#include "base/numerics/safe_conversions.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "components/cbor/cbor_constants.h" - -namespace cbor { - -namespace constants { -const char kUnsupportedMajorType[] = "Unsupported major type."; -} - -namespace { - -CBORValue::Type GetMajorType(uint8_t initial_data_byte) { - return static_cast( - (initial_data_byte & constants::kMajorTypeMask) >> - constants::kMajorTypeBitShift); -} - -uint8_t GetAdditionalInfo(uint8_t initial_data_byte) { - return initial_data_byte & constants::kAdditionalInformationMask; -} - -// Error messages that correspond to each of the error codes. There is 1 -// exception: we declare |kUnsupportedMajorType| in cbor_constants.h in the -// `constants` namespace, because we use it in several files. -const char kNoError[] = "Successfully deserialized to a CBOR value."; -const char kUnknownAdditionalInfo[] = - "Unknown additional info format in the first byte."; -const char kIncompleteCBORData[] = - "Prematurely terminated CBOR data byte array."; -const char kIncorrectMapKeyType[] = - "Specified map key type is not supported by the current implementation."; -const char kTooMuchNesting[] = "Too much nesting."; -const char kInvalidUTF8[] = "String encoding other than utf8 are not allowed."; -const char kExtraneousData[] = "Trailing data bytes are not allowed."; -const char kMapKeyOutOfOrder[] = - "Map keys must be strictly monotonically increasing based on byte length " - "and then by byte-wise lexical order."; -const char kNonMinimalCBOREncoding[] = - "Unsigned integers must be encoded with minimum number of bytes."; -const char kUnsupportedSimpleValue[] = - "Unsupported or unassigned simple value."; -const char kUnsupportedFloatingPointValue[] = - "Floating point numbers are not supported."; -const char kOutOfRangeIntegerValue[] = - "Integer values must be between INT64_MIN and INT64_MAX."; -const char kUnknownError[] = "An unknown error occured."; - -} // namespace - -CBORReader::CBORReader(base::span data) - : rest_(data), error_code_(DecoderError::CBOR_NO_ERROR) {} -CBORReader::~CBORReader() {} - -// static -base::Optional CBORReader::Read(base::span data, - DecoderError* error_code_out, - int max_nesting_level) { - size_t num_bytes_consumed; - auto decoded_cbor = - Read(data, &num_bytes_consumed, error_code_out, max_nesting_level); - - if (decoded_cbor && num_bytes_consumed != data.size()) { - if (error_code_out) - *error_code_out = DecoderError::EXTRANEOUS_DATA; - return base::nullopt; - } - - return decoded_cbor; -} - -// static -base::Optional CBORReader::Read(base::span data, - size_t* num_bytes_consumed, - DecoderError* error_code_out, - int max_nesting_level) { - CBORReader reader(data); - base::Optional decoded_cbor = - reader.DecodeCompleteDataItem(max_nesting_level); - - auto error_code = reader.GetErrorCode(); - const bool failed = !decoded_cbor.has_value(); - - // An error code must be set iff parsing failed. - DCHECK_EQ(failed, error_code != DecoderError::CBOR_NO_ERROR); - - if (error_code_out) - *error_code_out = error_code; - - *num_bytes_consumed = failed ? 0 : data.size() - reader.num_bytes_remaining(); - return decoded_cbor; -} - -base::Optional CBORReader::DecodeCompleteDataItem( - int max_nesting_level) { - if (max_nesting_level < 0 || max_nesting_level > kCBORMaxDepth) { - error_code_ = DecoderError::TOO_MUCH_NESTING; - return base::nullopt; - } - - base::Optional header = DecodeDataItemHeader(); - if (!header.has_value()) - return base::nullopt; - - switch (header->type) { - case CBORValue::Type::UNSIGNED: - return DecodeValueToUnsigned(header->value); - case CBORValue::Type::NEGATIVE: - return DecodeValueToNegative(header->value); - case CBORValue::Type::BYTE_STRING: - return ReadByteStringContent(*header); - case CBORValue::Type::STRING: - return ReadStringContent(*header); - case CBORValue::Type::ARRAY: - return ReadArrayContent(*header, max_nesting_level); - case CBORValue::Type::MAP: - return ReadMapContent(*header, max_nesting_level); - case CBORValue::Type::SIMPLE_VALUE: - return DecodeToSimpleValue(*header); - case CBORValue::Type::TAG: // We explicitly don't support TAG. - case CBORValue::Type::NONE: - break; - } - - error_code_ = DecoderError::UNSUPPORTED_MAJOR_TYPE; - return base::nullopt; -} - -base::Optional CBORReader::DecodeDataItemHeader() { - const base::Optional initial_byte = ReadByte(); - if (!initial_byte) { - return base::nullopt; - } - - const auto major_type = GetMajorType(initial_byte.value()); - const uint8_t additional_info = GetAdditionalInfo(initial_byte.value()); - - base::Optional value = ReadVariadicLengthInteger(additional_info); - return value ? base::make_optional( - DataItemHeader{major_type, additional_info, value.value()}) - : base::nullopt; -} - -base::Optional CBORReader::ReadVariadicLengthInteger( - uint8_t additional_info) { - uint8_t additional_bytes = 0; - if (additional_info < 24) { - return base::make_optional(additional_info); - } else if (additional_info == 24) { - additional_bytes = 1; - } else if (additional_info == 25) { - additional_bytes = 2; - } else if (additional_info == 26) { - additional_bytes = 4; - } else if (additional_info == 27) { - additional_bytes = 8; - } else { - error_code_ = DecoderError::UNKNOWN_ADDITIONAL_INFO; - return base::nullopt; - } - - const base::Optional> bytes = - ReadBytes(additional_bytes); - if (!bytes) { - return base::nullopt; - } - - uint64_t int_data = 0; - for (const uint8_t b : bytes.value()) { - int_data <<= 8; - int_data |= b; - } - - return CheckMinimalEncoding(additional_bytes, int_data) - ? base::make_optional(int_data) - : base::nullopt; -} - -base::Optional CBORReader::DecodeValueToNegative(uint64_t value) { - auto negative_value = -base::CheckedNumeric(value) - 1; - if (!negative_value.IsValid()) { - error_code_ = DecoderError::OUT_OF_RANGE_INTEGER_VALUE; - return base::nullopt; - } - return CBORValue(negative_value.ValueOrDie()); -} - -base::Optional CBORReader::DecodeValueToUnsigned(uint64_t value) { - auto unsigned_value = base::CheckedNumeric(value); - if (!unsigned_value.IsValid()) { - error_code_ = DecoderError::OUT_OF_RANGE_INTEGER_VALUE; - return base::nullopt; - } - return CBORValue(unsigned_value.ValueOrDie()); -} - -base::Optional CBORReader::DecodeToSimpleValue( - const DataItemHeader& header) { - // ReadVariadicLengthInteger provides this bound. - CHECK_LE(header.additional_info, 27); - // Floating point numbers are not supported. - if (header.additional_info > 24) { - error_code_ = DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE; - return base::nullopt; - } - - // Since |header.additional_info| <= 24, ReadVariadicLengthInteger also - // provides this bound for |header.value|. - CHECK_LE(header.value, 255u); - // |SimpleValue| is an enum class and so the underlying type is specified to - // be |int|. So this cast is safe. - CBORValue::SimpleValue possibly_unsupported_simple_value = - static_cast(static_cast(header.value)); - switch (possibly_unsupported_simple_value) { - case CBORValue::SimpleValue::FALSE_VALUE: - case CBORValue::SimpleValue::TRUE_VALUE: - case CBORValue::SimpleValue::NULL_VALUE: - case CBORValue::SimpleValue::UNDEFINED: - return CBORValue(possibly_unsupported_simple_value); - } - - error_code_ = DecoderError::UNSUPPORTED_SIMPLE_VALUE; - return base::nullopt; -} - -base::Optional CBORReader::ReadStringContent( - const CBORReader::DataItemHeader& header) { - uint64_t num_bytes = header.value; - const base::Optional> bytes = ReadBytes(num_bytes); - if (!bytes) { - return base::nullopt; - } - - std::string cbor_string(bytes->begin(), bytes->end()); - - return HasValidUTF8Format(cbor_string) - ? base::make_optional(CBORValue(std::move(cbor_string))) - : base::nullopt; -} - -base::Optional CBORReader::ReadByteStringContent( - const CBORReader::DataItemHeader& header) { - uint64_t num_bytes = header.value; - const base::Optional> bytes = ReadBytes(num_bytes); - if (!bytes) { - return base::nullopt; - } - - std::vector cbor_byte_string(bytes->begin(), bytes->end()); - return CBORValue(std::move(cbor_byte_string)); -} - -base::Optional CBORReader::ReadArrayContent( - const CBORReader::DataItemHeader& header, - int max_nesting_level) { - uint64_t length = header.value; - - CBORValue::ArrayValue cbor_array; - for (uint64_t i = 0; i < length; ++i) { - base::Optional cbor_element = - DecodeCompleteDataItem(max_nesting_level - 1); - if (!cbor_element.has_value()) - return base::nullopt; - cbor_array.push_back(std::move(cbor_element.value())); - } - return CBORValue(std::move(cbor_array)); -} - -base::Optional CBORReader::ReadMapContent( - const CBORReader::DataItemHeader& header, - int max_nesting_level) { - uint64_t length = header.value; - - CBORValue::MapValue cbor_map; - for (uint64_t i = 0; i < length; ++i) { - base::Optional key = - DecodeCompleteDataItem(max_nesting_level - 1); - base::Optional value = - DecodeCompleteDataItem(max_nesting_level - 1); - if (!key.has_value() || !value.has_value()) - return base::nullopt; - - switch (key.value().type()) { - case CBORValue::Type::UNSIGNED: - case CBORValue::Type::NEGATIVE: - case CBORValue::Type::STRING: - case CBORValue::Type::BYTE_STRING: - break; - default: - error_code_ = DecoderError::INCORRECT_MAP_KEY_TYPE; - return base::nullopt; - } - if (!CheckOutOfOrderKey(key.value(), &cbor_map)) { - return base::nullopt; - } - - cbor_map.insert_or_assign(std::move(key.value()), std::move(value.value())); - } - return CBORValue(std::move(cbor_map)); -} - -base::Optional CBORReader::ReadByte() { - const base::Optional> bytes = ReadBytes(1); - return bytes ? base::make_optional(bytes.value()[0]) : base::nullopt; -} - -base::Optional> CBORReader::ReadBytes( - uint64_t num_bytes) { - if (base::strict_cast(rest_.size()) < num_bytes) { - error_code_ = DecoderError::INCOMPLETE_CBOR_DATA; - return base::nullopt; - } - const base::span ret = rest_.first(num_bytes); - rest_ = rest_.subspan(num_bytes); - return ret; -} - -bool CBORReader::CheckMinimalEncoding(uint8_t additional_bytes, - uint64_t uint_data) { - if ((additional_bytes == 1 && uint_data < 24) || - uint_data <= (1ULL << 8 * (additional_bytes >> 1)) - 1) { - error_code_ = DecoderError::NON_MINIMAL_CBOR_ENCODING; - return false; - } - return true; -} - -bool CBORReader::HasValidUTF8Format(const std::string& string_data) { - if (!base::IsStringUTF8(string_data)) { - error_code_ = DecoderError::INVALID_UTF8; - return false; - } - return true; -} - -bool CBORReader::CheckOutOfOrderKey(const CBORValue& new_key, - CBORValue::MapValue* map) { - if (map->empty()) { - return true; - } - - const auto& max_current_key = map->rbegin()->first; - const auto less = map->key_comp(); - if (!less(max_current_key, new_key)) { - error_code_ = DecoderError::OUT_OF_ORDER_KEY; - return false; - } - return true; -} - -CBORReader::DecoderError CBORReader::GetErrorCode() { - return error_code_; -} - -// static -const char* CBORReader::ErrorCodeToString(DecoderError error) { - switch (error) { - case DecoderError::CBOR_NO_ERROR: - return kNoError; - case DecoderError::UNSUPPORTED_MAJOR_TYPE: - return constants::kUnsupportedMajorType; - case DecoderError::UNKNOWN_ADDITIONAL_INFO: - return kUnknownAdditionalInfo; - case DecoderError::INCOMPLETE_CBOR_DATA: - return kIncompleteCBORData; - case DecoderError::INCORRECT_MAP_KEY_TYPE: - return kIncorrectMapKeyType; - case DecoderError::TOO_MUCH_NESTING: - return kTooMuchNesting; - case DecoderError::INVALID_UTF8: - return kInvalidUTF8; - case DecoderError::EXTRANEOUS_DATA: - return kExtraneousData; - case DecoderError::OUT_OF_ORDER_KEY: - return kMapKeyOutOfOrder; - case DecoderError::NON_MINIMAL_CBOR_ENCODING: - return kNonMinimalCBOREncoding; - case DecoderError::UNSUPPORTED_SIMPLE_VALUE: - return kUnsupportedSimpleValue; - case DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE: - return kUnsupportedFloatingPointValue; - case DecoderError::OUT_OF_RANGE_INTEGER_VALUE: - return kOutOfRangeIntegerValue; - case DecoderError::UNKNOWN_ERROR: - return kUnknownError; - default: - NOTREACHED(); - return "Unknown error code."; - } -} - -} // namespace cbor diff --git a/chromium/components/cbor/cbor_reader.h b/chromium/components/cbor/cbor_reader.h deleted file mode 100644 index 1a1589cde72..00000000000 --- a/chromium/components/cbor/cbor_reader.h +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_CBOR_CBOR_READER_H_ -#define COMPONENTS_CBOR_CBOR_READER_H_ - -#include - -#include -#include - -#include "base/containers/span.h" -#include "base/optional.h" -#include "components/cbor/cbor_export.h" -#include "components/cbor/cbor_values.h" - -// Concise Binary Object Representation (CBOR) decoder as defined by -// https://tools.ietf.org/html/rfc7049. This decoder only accepts canonical CBOR -// as defined by section 3.9. -// -// This implementation supports the following major types: -// - 0: Unsigned integers, up to 64-bit values. -// - 1: Signed integers, up to 64-bit values. -// - 2: Byte strings. -// - 3: UTF-8 strings. -// - 4: Definite-length arrays. -// - 5: Definite-length maps. -// - 7: Simple values. -// -// Requirements for canonical CBOR representation: -// - Duplicate keys in maps are not allowed. -// - Keys for maps must be sorted first by length and then by byte-wise -// lexical order. -// -// Known limitations and interpretations of the RFC (and the reasons): -// - Does not support indefinite-length data streams or semantic tags (major -// type 6). (Simplicity; security) -// - Does not support the floating point and BREAK stop code value types in -// major type 7. (Simplicity) -// - Does not support non-character codepoints in major type 3. (Security) -// - Treats incomplete CBOR data items as syntax errors. (Security) -// - Treats trailing data bytes as errors. (Security) -// - Treats unknown additional information formats as syntax errors. -// (Simplicity; security) -// - Limits CBOR value inputs to at most 16 layers of nesting. Callers can -// enforce more shallow nesting by setting |max_nesting_level|. (Efficiency; -// security) -// - Only supports CBOR maps with integer or string type keys, due to the -// cost of serialization when sorting map keys. (Efficiency; simplicity) -// - Does not support simple values that are unassigned/reserved as per RFC -// 7049, and treats them as errors. (Security) - -namespace cbor { - -class CBOR_EXPORT CBORReader { - public: - enum class DecoderError { - CBOR_NO_ERROR = 0, - UNSUPPORTED_MAJOR_TYPE, - UNKNOWN_ADDITIONAL_INFO, - INCOMPLETE_CBOR_DATA, - INCORRECT_MAP_KEY_TYPE, - TOO_MUCH_NESTING, - INVALID_UTF8, - EXTRANEOUS_DATA, - OUT_OF_ORDER_KEY, - NON_MINIMAL_CBOR_ENCODING, - UNSUPPORTED_SIMPLE_VALUE, - UNSUPPORTED_FLOATING_POINT_VALUE, - OUT_OF_RANGE_INTEGER_VALUE, - UNKNOWN_ERROR, - }; - - // CBOR nested depth sufficient for most use cases. - static const int kCBORMaxDepth = 16; - - ~CBORReader(); - - // Reads and parses |input_data| into a CBORValue. Returns an empty Optional - // if the input violates any one of the syntax requirements (including unknown - // additional info and incomplete CBOR data). - // - // The caller can optionally provide |error_code_out| to obtain additional - // information about decoding failures. - // - // If the caller provides it, |max_nesting_level| cannot exceed - // |kCBORMaxDepth|. - // - // Returns an empty Optional if not all the data was consumed, and sets - // |error_code_out| to EXTRANEOUS_DATA in this case. - static base::Optional Read(base::span input_data, - DecoderError* error_code_out = nullptr, - int max_nesting_level = kCBORMaxDepth); - - // Never fails with EXTRANEOUS_DATA, but informs the caller of how many bytes - // were consumed through |num_bytes_consumed|. - static base::Optional Read(base::span input_data, - size_t* num_bytes_consumed, - DecoderError* error_code_out = nullptr, - int max_nesting_level = kCBORMaxDepth); - - // Translates errors to human-readable error messages. - static const char* ErrorCodeToString(DecoderError error_code); - - private: - explicit CBORReader(base::span data); - - // Encapsulates information extracted from the header of a CBOR data item, - // which consists of the initial byte, and a variable-length-encoded integer - // (if any). - struct DataItemHeader { - // The major type decoded from the initial byte. - CBORValue::Type type; - - // The raw 5-bit additional information from the initial byte. - uint8_t additional_info; - - // The integer |value| decoded from the |additional_info| and the - // variable-length-encoded integer, if any. - uint64_t value; - }; - - base::Optional DecodeDataItemHeader(); - base::Optional DecodeCompleteDataItem(int max_nesting_level); - base::Optional DecodeValueToNegative(uint64_t value); - base::Optional DecodeValueToUnsigned(uint64_t value); - base::Optional DecodeToSimpleValue(const DataItemHeader& header); - base::Optional ReadVariadicLengthInteger(uint8_t additional_info); - base::Optional ReadByteStringContent(const DataItemHeader& header); - base::Optional ReadStringContent(const DataItemHeader& header); - base::Optional ReadArrayContent(const DataItemHeader& header, - int max_nesting_level); - base::Optional ReadMapContent(const DataItemHeader& header, - int max_nesting_level); - base::Optional ReadByte(); - base::Optional> ReadBytes(uint64_t num_bytes); - // TODO(crbug/879237): This function's only caller has to make a copy of a - // `span` to satisfy this function's interface. Maybe we can make - // this function take a `const span` and avoid copying? - bool HasValidUTF8Format(const std::string& string_data); - bool CheckOutOfOrderKey(const CBORValue& new_key, CBORValue::MapValue* map); - bool CheckMinimalEncoding(uint8_t additional_bytes, uint64_t uint_data); - - DecoderError GetErrorCode(); - - size_t num_bytes_remaining() const { return rest_.size(); } - - base::span rest_; - DecoderError error_code_; - - DISALLOW_COPY_AND_ASSIGN(CBORReader); -}; - -} // namespace cbor - -#endif // COMPONENTS_CBOR_CBOR_READER_H_ diff --git a/chromium/components/cbor/cbor_reader_fuzzer.cc b/chromium/components/cbor/cbor_reader_fuzzer.cc deleted file mode 100644 index 4809e704adb..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include - -#include "components/cbor/cbor_reader.h" // nogncheck -#include "components/cbor/cbor_writer.h" // nogncheck - -namespace cbor { - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - std::vector input(data, data + size); - base::Optional cbor = CBORReader::Read(input); - - if (cbor.has_value()) { - base::Optional> serialized_cbor = - CBORWriter::Write(cbor.value()); - CHECK(serialized_cbor.has_value()); - if (serialized_cbor.has_value()) { - CHECK(serialized_cbor.value().size() == input.size()); - CHECK(memcmp(serialized_cbor.value().data(), input.data(), - input.size()) == 0); - } - } - return 0; -} - -} // namespace cbor diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor0 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor0 deleted file mode 100644 index f76dd238ade..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor0 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor1 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor1 deleted file mode 100644 index 6b2aaa76407..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor1 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor10 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor10 deleted file mode 100644 index fed1e13fcfa..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor10 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor11 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor11 deleted file mode 100644 index 00a3f0c5362..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor11 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor12 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor12 deleted file mode 100644 index 077457ad259..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor12 +++ /dev/null @@ -1 +0,0 @@ -; \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor13 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor13 deleted file mode 100644 index b4818a3b38b..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor13 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor14 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor14 deleted file mode 100644 index 0519ecba6ea..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor14 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor15 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor15 deleted file mode 100644 index e8a0f87653d..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor15 +++ /dev/null @@ -1 +0,0 @@ -) \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor16 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor16 deleted file mode 100644 index bfefdad18c4..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor16 +++ /dev/null @@ -1 +0,0 @@ -8c \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor17 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor17 deleted file mode 100644 index 5de255544fc..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor17 +++ /dev/null @@ -1 +0,0 @@ -9 \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor18 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor18 deleted file mode 100644 index e43ae5af822..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor18 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor19 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor19 deleted file mode 100644 index 6935671d0de..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor19 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor2 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor2 deleted file mode 100644 index 8b137891791..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor2 +++ /dev/null @@ -1 +0,0 @@ - diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor20 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor20 deleted file mode 100644 index ed788bb3a4c..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor20 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor21 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor21 deleted file mode 100644 index fc9ea00d188..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor21 +++ /dev/null @@ -1 +0,0 @@ -?񙙙 \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor22 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor22 deleted file mode 100644 index 5ac3929dea8..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor22 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor23 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor23 deleted file mode 100644 index 735f4675f10..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor23 +++ /dev/null @@ -1 +0,0 @@ -{ \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor24 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor24 deleted file mode 100644 index f36a086ed50..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor24 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor25 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor25 deleted file mode 100644 index 16f3345724b..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor25 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor26 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor26 deleted file mode 100644 index 8e79bf519fe..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor26 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor27 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor27 deleted file mode 100644 index 8e144ff3cd2..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor27 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor28 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor28 deleted file mode 100644 index 16b0d43402f..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor28 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor29 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor29 deleted file mode 100644 index e5b8b4d8adb..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor29 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor3 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor3 deleted file mode 100644 index c96ab3cc70e..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor3 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor30 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor30 deleted file mode 100644 index 815adc3e417..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor30 +++ /dev/null @@ -1 +0,0 @@ -ffffff \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor31 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor31 deleted file mode 100644 index 2b119eb6592..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor31 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor32 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor32 deleted file mode 100644 index d73f58e36a2..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor32 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor33 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor33 deleted file mode 100644 index 7c2eb64047e..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor33 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor34 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor34 deleted file mode 100644 index 82965f3b13a..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor34 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor35 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor35 deleted file mode 100644 index 2a9ccaec94a..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor35 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor36 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor36 deleted file mode 100644 index a9e0eebe00c..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor36 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor37 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor37 deleted file mode 100644 index c90d682d848..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor37 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor38 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor38 deleted file mode 100644 index 802efe1966e..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor38 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor39 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor39 deleted file mode 100644 index 7a1f61c5343..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor39 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor4 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor4 deleted file mode 100644 index a1910b3f6cc..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor4 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor40 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor40 deleted file mode 100644 index 3a6e607aa5a..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor40 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor41 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor41 deleted file mode 100644 index bb7d13c5e9a..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor41 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor42 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor42 deleted file mode 100644 index f7a8cadeb57..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor42 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor43 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor43 deleted file mode 100644 index 009080e8e0b..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor43 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor44 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor44 deleted file mode 100644 index 04f7b5be698..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor44 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor45 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor45 deleted file mode 100644 index 33c4e29de19..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor45 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor46 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor46 deleted file mode 100644 index a61a4624f2c..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor46 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor47 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor47 deleted file mode 100644 index d2fbff8927a..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor47 +++ /dev/null @@ -1 +0,0 @@ -t2013-03-21T20:04:00Z \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor48 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor48 deleted file mode 100644 index 4ecf94681e9..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor48 +++ /dev/null @@ -1 +0,0 @@ -QKg \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor49 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor49 deleted file mode 100644 index c5c79cf7779..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor49 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor5 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor5 deleted file mode 100644 index d4e634a6b50..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor5 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor50 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor50 deleted file mode 100644 index 7d0120d5bff..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor50 +++ /dev/null @@ -1 +0,0 @@ -D \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor51 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor51 deleted file mode 100644 index 2784fd87e9b..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor51 +++ /dev/null @@ -1 +0,0 @@ -EdIETF \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor52 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor52 deleted file mode 100644 index b7d2601ab13..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor52 +++ /dev/null @@ -1 +0,0 @@ - vhttp://www.example.com \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor53 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor53 deleted file mode 100644 index b516b2c489f..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor53 +++ /dev/null @@ -1 +0,0 @@ -@ \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor54 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor54 deleted file mode 100644 index 352e89a8017..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor54 +++ /dev/null @@ -1 +0,0 @@ -D \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor55 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor55 deleted file mode 100644 index 64845fb7679..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor55 +++ /dev/null @@ -1 +0,0 @@ -` \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor56 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor56 deleted file mode 100644 index 7ec9a4b774e..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor56 +++ /dev/null @@ -1 +0,0 @@ -aa \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor57 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor57 deleted file mode 100644 index 743669bb19c..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor57 +++ /dev/null @@ -1 +0,0 @@ -dIETF \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor58 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor58 deleted file mode 100644 index cce6615381d..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor58 +++ /dev/null @@ -1 +0,0 @@ -b"\ \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor59 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor59 deleted file mode 100644 index 9055a92aa61..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor59 +++ /dev/null @@ -1 +0,0 @@ -bü \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor6 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor6 deleted file mode 100644 index 3b5c90718af..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor6 +++ /dev/null @@ -1 +0,0 @@ -d \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor60 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor60 deleted file mode 100644 index 0868c9a4288..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor60 +++ /dev/null @@ -1 +0,0 @@ -c水 \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor61 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor61 deleted file mode 100644 index 8ea48a07a27..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor61 +++ /dev/null @@ -1 +0,0 @@ -d𐅑 \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor62 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor62 deleted file mode 100644 index 5416677bc7d..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor62 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor63 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor63 deleted file mode 100644 index 4cdf6ce18a8..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor63 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor64 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor64 deleted file mode 100644 index 80fd3949e51..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor64 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor65 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor65 deleted file mode 100644 index b4495842ec6..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor65 +++ /dev/null @@ -1,2 +0,0 @@ - -  \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor66 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor66 deleted file mode 100644 index eea1bf0c31f..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor66 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor67 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor67 deleted file mode 100644 index abc169a8cc5..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor67 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor68 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor68 deleted file mode 100644 index 81e38473ff6..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor68 +++ /dev/null @@ -1 +0,0 @@ -aaab \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor69 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor69 deleted file mode 100644 index 9b1d08caf44..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor69 +++ /dev/null @@ -1 +0,0 @@ -aaabac \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor7 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor7 deleted file mode 100644 index fda74fd9c88..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor7 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor70 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor70 deleted file mode 100644 index 05bb07fc9d1..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor70 +++ /dev/null @@ -1 +0,0 @@ -aaaAabaBacaCadaDaeaE \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor71 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor71 deleted file mode 100644 index 2681a857cb7..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor71 +++ /dev/null @@ -1 +0,0 @@ -_BC \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor72 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor72 deleted file mode 100644 index d0daf282398..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor72 +++ /dev/null @@ -1 +0,0 @@ -estreadming \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor73 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor73 deleted file mode 100644 index 422ce24eaac..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor73 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor74 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor74 deleted file mode 100644 index f67cd5703a8..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor74 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor75 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor75 deleted file mode 100644 index 78343ed40e3..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor75 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor76 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor76 deleted file mode 100644 index a0f1ea25969..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor76 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor77 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor77 deleted file mode 100644 index dbbf8e51a3f..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor77 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor78 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor78 deleted file mode 100644 index 81c9910e824..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor78 +++ /dev/null @@ -1,2 +0,0 @@ - -  \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor79 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor79 deleted file mode 100644 index 018602c1e13..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor79 +++ /dev/null @@ -1 +0,0 @@ -aaab \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor8 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor8 deleted file mode 100644 index 916281951cd..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor8 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor80 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor80 deleted file mode 100644 index 151c13e53d3..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor80 +++ /dev/null @@ -1 +0,0 @@ -aaabac \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor81 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor81 deleted file mode 100644 index c0f4fd5eb32..00000000000 --- a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor81 +++ /dev/null @@ -1 +0,0 @@ -cFuncAmt! \ No newline at end of file diff --git a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor9 b/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor9 deleted file mode 100644 index 4cdcd7ccc3f..00000000000 Binary files a/chromium/components/cbor/cbor_reader_fuzzer_corpus/cbor9 and /dev/null differ diff --git a/chromium/components/cbor/cbor_reader_unittest.cc b/chromium/components/cbor/cbor_reader_unittest.cc deleted file mode 100644 index d86866d3048..00000000000 --- a/chromium/components/cbor/cbor_reader_unittest.cc +++ /dev/null @@ -1,1250 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include - -#include "components/cbor/cbor_reader.h" - -#include "base/containers/span.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -/* Leveraging RFC 7049 examples from - https://github.com/cbor/test-vectors/blob/master/appendix_a.json. */ -namespace cbor { - -namespace { - -std::vector WithExtraneousData(base::span original) { - std::vector ret(original.cbegin(), original.cend()); - // Add a valid one byte long CBOR data item, namely, an unsigned integer - // with value "1". - ret.push_back(0x01); - return ret; -} - -} // namespace - -TEST(CBORReaderTest, TestReadUint) { - struct UintTestCase { - const int64_t value; - const std::vector cbor_data; - }; - - static const UintTestCase kUintTestCases[] = { - {0, {0x00}}, - {1, {0x01}}, - {23, {0x17}}, - {24, {0x18, 0x18}}, - {std::numeric_limits::max(), {0x18, 0xff}}, - {1LL << 8, {0x19, 0x01, 0x00}}, - {std::numeric_limits::max(), {0x19, 0xff, 0xff}}, - {1LL << 16, {0x1a, 0x00, 0x01, 0x00, 0x00}}, - {std::numeric_limits::max(), {0x1a, 0xff, 0xff, 0xff, 0xff}}, - {1LL << 32, {0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, - {std::numeric_limits::max(), - {0x1b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}, - }; - - for (const UintTestCase& test_case : kUintTestCases) { - SCOPED_TRACE(testing::Message() << "testing uint: " << test_case.value); - - base::Optional cbor = CBORReader::Read(test_case.cbor_data); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::UNSIGNED); - EXPECT_EQ(cbor.value().GetInteger(), test_case.value); - - auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::UNSIGNED); - EXPECT_EQ(cbor.value().GetInteger(), test_case.value); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); - } -} - -TEST(CBORReaderTest, TestUintEncodedWithNonMinimumByteLength) { - static const std::vector non_minimal_uint_encodings[] = { - // Uint 23 encoded with 1 byte. - {0x18, 0x17}, - // Uint 255 encoded with 2 bytes. - {0x19, 0x00, 0xff}, - // Uint 65535 encoded with 4 byte. - {0x1a, 0x00, 0x00, 0xff, 0xff}, - // Uint 4294967295 encoded with 8 byte. - {0x1b, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}, - - // When decoding byte has more than one syntax error, the first syntax - // error encountered during deserialization is returned as the error code. - { - 0xa2, // map with non-minimally encoded key - 0x17, // key 24 - 0x61, 0x42, // value :"B" - - 0x18, 0x17, // key 23 encoded with extra byte - 0x61, 0x45 // value "E" - }, - { - 0xa2, // map with out of order and non-minimally encoded key - 0x18, 0x17, // key 23 encoded with extra byte - 0x61, 0x45, // value "E" - 0x17, // key 23 - 0x61, 0x42 // value :"B" - }, - { - 0xa2, // map with duplicate non-minimally encoded key - 0x18, 0x17, // key 23 encoded with extra byte - 0x61, 0x45, // value "E" - 0x18, 0x17, // key 23 encoded with extra byte - 0x61, 0x42 // value :"B" - }, - }; - - int test_case_index = 0; - CBORReader::DecoderError error_code; - for (const auto& non_minimal_uint : non_minimal_uint_encodings) { - SCOPED_TRACE(testing::Message() - << "testing element at index : " << test_case_index++); - - base::Optional cbor = - CBORReader::Read(non_minimal_uint, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::NON_MINIMAL_CBOR_ENCODING); - } -} - -TEST(CBORReaderTest, TestReadNegativeInt) { - struct NegativeIntTestCase { - const int64_t negative_int; - const std::vector cbor_data; - }; - - static const NegativeIntTestCase kNegativeIntTestCases[] = { - {-1LL, {0x20}}, - {-24LL, {0x37}}, - {-25LL, {0x38, 0x18}}, - {-256LL, {0x38, 0xff}}, - {-1000LL, {0x39, 0x03, 0xe7}}, - {-1000000LL, {0x3a, 0x00, 0x0f, 0x42, 0x3f}}, - {-4294967296LL, {0x3a, 0xff, 0xff, 0xff, 0xff}}, - {std::numeric_limits::min(), - {0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}}; - - for (const NegativeIntTestCase& test_case : kNegativeIntTestCases) { - SCOPED_TRACE(testing::Message() - << "testing negative int : " << test_case.negative_int); - - base::Optional cbor = CBORReader::Read(test_case.cbor_data); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::NEGATIVE); - EXPECT_EQ(cbor.value().GetInteger(), test_case.negative_int); - - auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::NEGATIVE); - EXPECT_EQ(cbor.value().GetInteger(), test_case.negative_int); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); - } -} - -TEST(CBORReaderTest, TestReadBytes) { - struct ByteTestCase { - const std::vector value; - const std::vector cbor_data; - }; - - static const ByteTestCase kByteStringTestCases[] = { - // clang-format off - {{}, {0x40}}, - {{0x01, 0x02, 0x03, 0x04}, {0x44, 0x01, 0x02, 0x03, 0x04}}, - // clang-format on - }; - - int element_index = 0; - for (const ByteTestCase& test_case : kByteStringTestCases) { - SCOPED_TRACE(testing::Message() - << "testing string test case at : " << element_index++); - - base::Optional cbor = CBORReader::Read(test_case.cbor_data); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::BYTE_STRING); - EXPECT_EQ(cbor.value().GetBytestring(), test_case.value); - - auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::BYTE_STRING); - EXPECT_EQ(cbor.value().GetBytestring(), test_case.value); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); - } -} - -TEST(CBORReaderTest, TestReadString) { - struct StringTestCase { - const std::string value; - const std::vector cbor_data; - }; - - static const StringTestCase kStringTestCases[] = { - {"", {0x60}}, - {"a", {0x61, 0x61}}, - {"IETF", {0x64, 0x49, 0x45, 0x54, 0x46}}, - {"\"\\", {0x62, 0x22, 0x5c}}, - {"\xc3\xbc", {0x62, 0xc3, 0xbc}}, - {"\xe6\xb0\xb4", {0x63, 0xe6, 0xb0, 0xb4}}, - {"\xf0\x90\x85\x91", {0x64, 0xf0, 0x90, 0x85, 0x91}}, - }; - - for (const StringTestCase& test_case : kStringTestCases) { - SCOPED_TRACE(testing::Message() - << "testing string value : " << test_case.value); - - base::Optional cbor = CBORReader::Read(test_case.cbor_data); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING); - EXPECT_EQ(cbor.value().GetString(), test_case.value); - - auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING); - EXPECT_EQ(cbor.value().GetString(), test_case.value); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); - } -} - -TEST(CBORReaderTest, TestReadStringWithNUL) { - static const struct { - const std::string value; - const std::vector cbor_data; - } kStringTestCases[] = { - {std::string("string_without_nul"), - {0x72, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x5F, 0x77, 0x69, 0x74, 0x68, - 0x6F, 0x75, 0x74, 0x5F, 0x6E, 0x75, 0x6C}}, - {std::string("nul_terminated_string\0", 22), - {0x76, 0x6E, 0x75, 0x6C, 0x5F, 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x61, - 0x74, 0x65, 0x64, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00}}, - {std::string("embedded\0nul", 12), - {0x6C, 0x65, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x00, 0x6E, 0x75, - 0x6C}}, - {std::string("trailing_nuls\0\0", 15), - {0x6F, 0x74, 0x72, 0x61, 0x69, 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x6E, 0x75, - 0x6C, 0x73, 0x00, 0x00}}, - }; - - for (const auto& test_case : kStringTestCases) { - SCOPED_TRACE(testing::Message() - << "testing string with nul bytes :" << test_case.value); - - base::Optional cbor = CBORReader::Read(test_case.cbor_data); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING); - EXPECT_EQ(cbor.value().GetString(), test_case.value); - - auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING); - EXPECT_EQ(cbor.value().GetString(), test_case.value); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); - } -} - -TEST(CBORReaderTest, TestReadStringWithInvalidByteSequenceAfterNUL) { - // UTF-8 validation should not stop at the first NUL character in the string. - // That is, a string with an invalid byte sequence should fail UTF-8 - // validation even if the invalid character is located after one or more NUL - // characters. Here, 0xA6 is an unexpected continuation byte. - static const std::vector string_with_invalid_continuation_byte = { - 0x63, 0x00, 0x00, 0xA6}; - CBORReader::DecoderError error_code; - base::Optional cbor = - CBORReader::Read(string_with_invalid_continuation_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::INVALID_UTF8); -} - -TEST(CBORReaderTest, TestReadArray) { - static const std::vector kArrayTestCaseCbor = { - // clang-format off - 0x98, 0x19, // array of 25 elements - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, - 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x18, 0x18, 0x19, - // clang-format on - }; - - base::Optional cbor = CBORReader::Read(kArrayTestCaseCbor); - ASSERT_TRUE(cbor.has_value()); - const CBORValue cbor_array = std::move(cbor.value()); - ASSERT_EQ(cbor_array.type(), CBORValue::Type::ARRAY); - ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25)); - - std::vector array; - for (int i = 0; i < 25; i++) { - SCOPED_TRACE(testing::Message() << "testing array element at index " << i); - - ASSERT_EQ(cbor_array.GetArray()[i].type(), CBORValue::Type::UNSIGNED); - EXPECT_EQ(cbor_array.GetArray()[i].GetInteger(), - static_cast(i + 1)); - } - - auto cbor_data_with_extra_byte = WithExtraneousData(kArrayTestCaseCbor); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor_array.type(), CBORValue::Type::ARRAY); - ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25)); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, kArrayTestCaseCbor.size()); -} - -TEST(CBORReaderTest, TestReadMapWithMapValue) { - static const std::vector kMapTestCaseCbor = { - // clang-format off - 0xa4, // map with 4 key value pairs: - 0x18, 0x18, // 24 - 0x63, 0x61, 0x62, 0x63, // "abc" - - 0x60, // "" - 0x61, 0x2e, // "." - - 0x61, 0x62, // "b" - 0x61, 0x42, // "B" - - 0x62, 0x61, 0x61, // "aa" - 0x62, 0x41, 0x41, // "AA" - // clang-format on - }; - - base::Optional cbor = CBORReader::Read(kMapTestCaseCbor); - ASSERT_TRUE(cbor.has_value()); - const CBORValue cbor_val = std::move(cbor.value()); - ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor_val.GetMap().size(), 4u); - - const CBORValue key_uint(24); - ASSERT_EQ(cbor_val.GetMap().count(key_uint), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_uint)->second.type(), - CBORValue::Type::STRING); - EXPECT_EQ(cbor_val.GetMap().find(key_uint)->second.GetString(), "abc"); - - const CBORValue key_empty_string(""); - ASSERT_EQ(cbor_val.GetMap().count(key_empty_string), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_empty_string)->second.type(), - CBORValue::Type::STRING); - EXPECT_EQ(cbor_val.GetMap().find(key_empty_string)->second.GetString(), "."); - - const CBORValue key_b("b"); - ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(), - CBORValue::Type::STRING); - EXPECT_EQ(cbor_val.GetMap().find(key_b)->second.GetString(), "B"); - - const CBORValue key_aa("aa"); - ASSERT_EQ(cbor_val.GetMap().count(key_aa), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_aa)->second.type(), - CBORValue::Type::STRING); - EXPECT_EQ(cbor_val.GetMap().find(key_aa)->second.GetString(), "AA"); - - auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCaseCbor); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor_val.GetMap().size(), 4u); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, kMapTestCaseCbor.size()); -} - -TEST(CBORReaderTest, TestReadMapWithIntegerKeys) { - static const std::vector kMapWithIntegerKeyCbor = { - // clang-format off - 0xA4, // map with 4 key value pairs - 0x01, // key : 1 - 0x61, 0x61, // value : "a" - - 0x09, // key : 9 - 0x61, 0x62, // value : "b" - - 0x19, 0x03, 0xE7, // key : 999 - 0x61, 0x63, // value "c" - - 0x19, 0x04, 0x57, // key : 1111 - 0x61, 0x64, // value : "d" - // clang-format on - }; - - base::Optional cbor = CBORReader::Read(kMapWithIntegerKeyCbor); - ASSERT_TRUE(cbor.has_value()); - const CBORValue cbor_val = std::move(cbor.value()); - ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor_val.GetMap().size(), 4u); - - const CBORValue key_1(1); - ASSERT_EQ(cbor_val.GetMap().count(key_1), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(), - CBORValue::Type::STRING); - EXPECT_EQ(cbor_val.GetMap().find(key_1)->second.GetString(), "a"); - - const CBORValue key_9(9); - ASSERT_EQ(cbor_val.GetMap().count(key_9), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_9)->second.type(), - CBORValue::Type::STRING); - EXPECT_EQ(cbor_val.GetMap().find(key_9)->second.GetString(), "b"); - - const CBORValue key_999(999); - ASSERT_EQ(cbor_val.GetMap().count(key_999), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_999)->second.type(), - CBORValue::Type::STRING); - EXPECT_EQ(cbor_val.GetMap().find(key_999)->second.GetString(), "c"); - - const CBORValue key_1111(1111); - ASSERT_EQ(cbor_val.GetMap().count(key_1111), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_1111)->second.type(), - CBORValue::Type::STRING); - EXPECT_EQ(cbor_val.GetMap().find(key_1111)->second.GetString(), "d"); - - auto cbor_data_with_extra_byte = WithExtraneousData(kMapWithIntegerKeyCbor); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor_val.GetMap().size(), 4u); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, kMapWithIntegerKeyCbor.size()); -} - -TEST(CBORReaderTest, TestReadMapWithNegativeIntegersKeys) { - static const std::vector kMapWithIntegerKeyCbor = { - // clang-format off - 0xA3, // map with 3 key value pairs - 0x20, // key : -1 - 0x01, - - 0x21, // key : -2 - 0x02, - - 0x38, 0x63, // key : -100 - 0x03, - // clang-format on - }; - - base::Optional cbor = CBORReader::Read(kMapWithIntegerKeyCbor); - ASSERT_TRUE(cbor.has_value()); - const CBORValue cbor_val = std::move(cbor.value()); - ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor_val.GetMap().size(), 3u); - - const CBORValue key_1(-1); - ASSERT_EQ(cbor_val.GetMap().count(key_1), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(), - CBORValue::Type::UNSIGNED); - EXPECT_EQ(cbor_val.GetMap().find(key_1)->second.GetInteger(), 1); - - const CBORValue key_2(-2); - ASSERT_EQ(cbor_val.GetMap().count(key_2), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_2)->second.type(), - CBORValue::Type::UNSIGNED); - EXPECT_EQ(cbor_val.GetMap().find(key_2)->second.GetInteger(), 2); - - const CBORValue key_100(-100); - ASSERT_EQ(cbor_val.GetMap().count(key_100), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_100)->second.type(), - CBORValue::Type::UNSIGNED); - EXPECT_EQ(cbor_val.GetMap().find(key_100)->second.GetInteger(), 3); - - auto cbor_data_with_extra_byte = WithExtraneousData(kMapWithIntegerKeyCbor); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor_val.GetMap().size(), 3u); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, kMapWithIntegerKeyCbor.size()); -} - -TEST(CBORReaderTest, TestReadMapWithArray) { - static const std::vector kMapArrayTestCaseCbor = { - // clang-format off - 0xa2, // map of 2 pairs - 0x61, 0x61, // "a" - 0x01, - - 0x61, 0x62, // "b" - 0x82, // array with 2 elements - 0x02, - 0x03, - // clang-format on - }; - - base::Optional cbor = CBORReader::Read(kMapArrayTestCaseCbor); - ASSERT_TRUE(cbor.has_value()); - const CBORValue cbor_val = std::move(cbor.value()); - ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor_val.GetMap().size(), 2u); - - const CBORValue key_a("a"); - ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(), - CBORValue::Type::UNSIGNED); - EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u); - - const CBORValue key_b("b"); - ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(), - CBORValue::Type::ARRAY); - - const CBORValue nested_array = cbor_val.GetMap().find(key_b)->second.Clone(); - ASSERT_EQ(nested_array.GetArray().size(), 2u); - for (int i = 0; i < 2; i++) { - ASSERT_THAT(nested_array.GetArray()[i].type(), CBORValue::Type::UNSIGNED); - EXPECT_EQ(nested_array.GetArray()[i].GetInteger(), - static_cast(i + 2)); - } - - auto cbor_data_with_extra_byte = WithExtraneousData(kMapArrayTestCaseCbor); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor_val.GetMap().size(), 2u); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, kMapArrayTestCaseCbor.size()); -} - -TEST(CBORReaderTest, TestReadMapWithTextStringKeys) { - static const std::vector kMapTestCase{ - // clang-format off - 0xa2, // map of 2 pairs - 0x61, 'k', // text string "k" - 0x61, 'v', - - 0x63, 'f', 'o', 'o', // text string "foo" - 0x63, 'b', 'a', 'r', - // clang-format on - }; - - CBORReader::DecoderError error_code; - base::Optional cbor = CBORReader::Read(kMapTestCase, &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor->type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor->GetMap().size(), 2u); - - const CBORValue key_k("k"); - ASSERT_EQ(cbor->GetMap().count(key_k), 1u); - ASSERT_EQ(cbor->GetMap().find(key_k)->second.type(), CBORValue::Type::STRING); - EXPECT_EQ(cbor->GetMap().find(key_k)->second.GetString(), "v"); - - const CBORValue key_foo("foo"); - ASSERT_EQ(cbor->GetMap().count(key_foo), 1u); - ASSERT_EQ(cbor->GetMap().find(key_foo)->second.type(), - CBORValue::Type::STRING); - EXPECT_EQ(cbor->GetMap().find(key_foo)->second.GetString(), "bar"); - - auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase); - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor->type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor->GetMap().size(), 2u); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, kMapTestCase.size()); -} - -TEST(CBORReaderTest, TestReadMapWithByteStringKeys) { - static const std::vector kMapTestCase{ - // clang-format off - 0xa2, // map of 2 pairs - 0x41, 'k', // byte string "k" - 0x41, 'v', - - 0x43, 'f', 'o', 'o', // byte string "foo" - 0x43, 'b', 'a', 'r', - // clang-format on - }; - - CBORReader::DecoderError error_code; - base::Optional cbor = CBORReader::Read(kMapTestCase, &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor->type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor->GetMap().size(), 2u); - - const CBORValue key_k(std::vector{'k'}); - ASSERT_EQ(cbor->GetMap().count(key_k), 1u); - ASSERT_EQ(cbor->GetMap().find(key_k)->second.type(), - CBORValue::Type::BYTE_STRING); - EXPECT_EQ(cbor->GetMap().find(key_k)->second.GetBytestring(), - std::vector{'v'}); - - const CBORValue key_foo(std::vector{'f', 'o', 'o'}); - ASSERT_EQ(cbor->GetMap().count(key_foo), 1u); - ASSERT_EQ(cbor->GetMap().find(key_foo)->second.type(), - CBORValue::Type::BYTE_STRING); - static const std::vector kBarBytes{'b', 'a', 'r'}; - EXPECT_EQ(cbor->GetMap().find(key_foo)->second.GetBytestring(), kBarBytes); - - auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase); - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor->type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor->GetMap().size(), 2u); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, kMapTestCase.size()); -} - -TEST(CBORReaderTest, TestReadMapWithMixedKeys) { - // Example adopted from: - // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html - static const uint8_t kMapTestCase[] = { - // clang-format off - 0xa6, // map of 6 pairs - 0x0a, // 10 - 0x00, - - 0x18, 0x64, // 100 - 0x01, - - 0x20, // -1 - 0x02, - - // This entry is not in the example, but added to test byte string key - 0x42, 'x', 'y', // byte string "xy" - 0x03, - - 0x61, 'z', // text string "z" - 0x04, - - 0x62, 'a', 'a', // text string "aa" - 0x05, - - /* - 0x81, 0x18, 0x64, // [100] (array as map key is not yet supported) - 0x06, - - 0x81, 0x20, // [-1] (array as map key is not yet supported) - 0x07, - - 0xf4, // false (boolean as map key is not yet supported) - 0x08, - */ - // clang-format on - }; - - CBORReader::DecoderError error_code; - base::Optional cbor = CBORReader::Read(kMapTestCase, &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor->type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor->GetMap().size(), 6u); - - std::vector keys; - keys.emplace_back(10); - keys.emplace_back(100); - keys.emplace_back(-1); - keys.emplace_back(CBORValue::BinaryValue{'x', 'y'}); - keys.emplace_back("z"); - keys.emplace_back("aa"); - for (size_t i = 0; i < keys.size(); ++i) { - SCOPED_TRACE(testing::Message() << "testing key at index: " << i); - ASSERT_EQ(cbor->GetMap().count(keys[i]), 1u); - ASSERT_EQ(cbor->GetMap().find(keys[i])->second.type(), - CBORValue::Type::UNSIGNED); - EXPECT_EQ(cbor->GetMap().find(keys[i])->second.GetInteger(), - static_cast(i)); - } - - auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase); - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor->type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor->GetMap().size(), 6u); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, arraysize(kMapTestCase)); -} - -TEST(CBORReaderTest, TestReadNestedMap) { - static const std::vector kNestedMapTestCase = { - // clang-format off - 0xa2, // map of 2 pairs - 0x61, 0x61, // "a" - 0x01, - - 0x61, 0x62, // "b" - 0xa2, // map of 2 pairs - 0x61, 0x63, // "c" - 0x02, - - 0x61, 0x64, // "d" - 0x03, - // clang-format on - }; - - base::Optional cbor = CBORReader::Read(kNestedMapTestCase); - ASSERT_TRUE(cbor.has_value()); - const CBORValue cbor_val = std::move(cbor.value()); - ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP); - ASSERT_EQ(cbor_val.GetMap().size(), 2u); - - const CBORValue key_a("a"); - ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u); - ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(), - CBORValue::Type::UNSIGNED); - EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u); - - const CBORValue key_b("b"); - ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u); - const CBORValue nested_map = cbor_val.GetMap().find(key_b)->second.Clone(); - ASSERT_EQ(nested_map.type(), CBORValue::Type::MAP); - ASSERT_EQ(nested_map.GetMap().size(), 2u); - - const CBORValue key_c("c"); - ASSERT_EQ(nested_map.GetMap().count(key_c), 1u); - ASSERT_EQ(nested_map.GetMap().find(key_c)->second.type(), - CBORValue::Type::UNSIGNED); - EXPECT_EQ(nested_map.GetMap().find(key_c)->second.GetInteger(), 2u); - - const CBORValue key_d("d"); - ASSERT_EQ(nested_map.GetMap().count(key_d), 1u); - ASSERT_EQ(nested_map.GetMap().find(key_d)->second.type(), - CBORValue::Type::UNSIGNED); - EXPECT_EQ(nested_map.GetMap().find(key_d)->second.GetInteger(), 3u); -} - -TEST(CBORReaderTest, TestIntegerRange) { - static const std::vector kMaxPositiveInt = { - 0x1b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - static const std::vector kMinNegativeInt = { - 0x3b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - - base::Optional max_positive_int = - CBORReader::Read(kMaxPositiveInt); - ASSERT_TRUE(max_positive_int.has_value()); - EXPECT_EQ(max_positive_int.value().GetInteger(), INT64_MAX); - - base::Optional min_negative_int = - CBORReader::Read(kMinNegativeInt); - ASSERT_TRUE(min_negative_int.has_value()); - EXPECT_EQ(min_negative_int.value().GetInteger(), INT64_MIN); -} - -TEST(CBORReaderTest, TestIntegerOutOfRangeError) { - static const std::vector kOutOfRangePositiveInt = { - 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - static const std::vector kOutOfRangeNegativeInt = { - 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - CBORReader::DecoderError error_code; - base::Optional positive_int_out_of_range_cbor = - CBORReader::Read(kOutOfRangePositiveInt, &error_code); - EXPECT_FALSE(positive_int_out_of_range_cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE); - - base::Optional negative_int_out_of_range_cbor = - CBORReader::Read(kOutOfRangeNegativeInt, &error_code); - EXPECT_FALSE(negative_int_out_of_range_cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE); -} - -TEST(CBORReaderTest, TestReadSimpleValue) { - static const struct { - const CBORValue::SimpleValue value; - const std::vector cbor_data; - } kSimpleValueTestCases[] = { - {CBORValue::SimpleValue::FALSE_VALUE, {0xf4}}, - {CBORValue::SimpleValue::TRUE_VALUE, {0xf5}}, - {CBORValue::SimpleValue::NULL_VALUE, {0xf6}}, - {CBORValue::SimpleValue::UNDEFINED, {0xf7}}, - }; - - int test_element_index = 0; - for (const auto& test_case : kSimpleValueTestCases) { - SCOPED_TRACE(testing::Message() - << "testing simple value at index : " << test_element_index++); - - base::Optional cbor = CBORReader::Read(test_case.cbor_data); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::SIMPLE_VALUE); - EXPECT_EQ(cbor.value().GetSimpleValue(), test_case.value); - - auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); - CBORReader::DecoderError error_code; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - - size_t num_bytes_consumed; - cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, - &error_code); - ASSERT_TRUE(cbor.has_value()); - ASSERT_EQ(cbor.value().type(), CBORValue::Type::SIMPLE_VALUE); - EXPECT_EQ(cbor.value().GetSimpleValue(), test_case.value); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); - } -} - -TEST(CBORReaderTest, TestReadUnsupportedFloatingPointNumbers) { - static const std::vector floating_point_cbors[] = { - // 16 bit floating point value. - {0xf9, 0x10, 0x00}, - // 32 bit floating point value. - {0xfa, 0x10, 0x00, 0x00, 0x00}, - // 64 bit floating point value. - {0xfb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - - for (const auto& unsupported_floating_point : floating_point_cbors) { - SCOPED_TRACE(testing::Message() - << "testing unsupported floating point : " - << testing::PrintToString(unsupported_floating_point)); - CBORReader::DecoderError error_code; - base::Optional cbor = - CBORReader::Read(unsupported_floating_point, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, - CBORReader::DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE); - } -} - -TEST(CBORReaderTest, TestIncompleteCBORDataError) { - static const std::vector incomplete_cbor_list[] = { - // Additional info byte corresponds to unsigned int that corresponds - // to 2 additional bytes. But actual data encoded in one byte. - {0x19, 0x03}, - // CBOR bytestring of length 3 encoded with additional info of length 4. - {0x44, 0x01, 0x02, 0x03}, - // CBOR string data "IETF" of length 4 encoded with additional info of - // length 5. - {0x65, 0x49, 0x45, 0x54, 0x46}, - // CBOR array of length 1 encoded with additional info of length 2. - {0x82, 0x02}, - // CBOR map with single key value pair encoded with additional info of - // length 2. - {0xa2, 0x61, 0x61, 0x01}, - {0x18}, // unsigned with pending 1 byte of numeric value. - {0x99}, // array with pending 2 byte of numeric value (length). - {0xba}, // map with pending 4 byte of numeric value (length). - {0x5b}, // byte string with pending 4 byte of numeric value (length). - {0x3b}, // negative integer with pending 8 byte of numeric value. - {0x99, 0x01}, // array with pending 2 byte of numeric value (length), - // with only 1 byte of additional data. - {0xba, 0x01, 0x02, 0x03}, // map with pending 4 byte of numeric value - // (length), with only 3 bytes of additional - // data. - {0x3b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07}, // negative integer with pending 8 byte of - // numeric value, with only 7 bytes of - // additional data. - }; - - int test_element_index = 0; - for (const auto& incomplete_data : incomplete_cbor_list) { - SCOPED_TRACE(testing::Message() << "testing incomplete data at index : " - << test_element_index++); - - CBORReader::DecoderError error_code; - base::Optional cbor = - CBORReader::Read(incomplete_data, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::INCOMPLETE_CBOR_DATA); - } -} - -// While RFC 7049 allows CBOR map keys with all types, current decoder only -// supports unsigned integer and string keys. -TEST(CBORReaderTest, TestUnsupportedMapKeyFormatError) { - static const std::vector kMapWithUintKey = { - // clang-format off - 0xa2, // map of 2 pairs - - 0x82, 0x01, 0x02, // invalid key : [1, 2] - 0x02, // value : 2 - - 0x61, 0x64, // key : "d" - 0x03, // value : 3 - // clang-format on - }; - - CBORReader::DecoderError error_code; - base::Optional cbor = - CBORReader::Read(kMapWithUintKey, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::INCORRECT_MAP_KEY_TYPE); -} - -TEST(CBORReaderTest, TestUnknownAdditionalInfoError) { - static const std::vector kUnknownAdditionalInfoList[] = { - // "IETF" encoded with major type 3 and additional info of 28. - {0x7C, 0x49, 0x45, 0x54, 0x46}, - // "\"\\" encoded with major type 3 and additional info of 29. - {0x7D, 0x22, 0x5c}, - // "\xc3\xbc" encoded with major type 3 and additional info of 30. - {0x7E, 0xc3, 0xbc}, - // "\xe6\xb0\xb4" encoded with major type 3 and additional info of 31. - {0x7F, 0xe6, 0xb0, 0xb4}, - // Major type 7, additional information 28: unassigned. - {0xFC}, - // Major type 7, additional information 29: unassigned. - {0xFD}, - // Major type 7, additional information 30: unassigned. - {0xFE}, - // Major type 7, additional information 31: "break" stop code for - // indefinite-length items. - {0xFF}, - }; - - int test_element_index = 0; - for (const auto& incorrect_cbor : kUnknownAdditionalInfoList) { - SCOPED_TRACE(testing::Message() - << "testing data at index : " << test_element_index++); - - CBORReader::DecoderError error_code; - base::Optional cbor = - CBORReader::Read(incorrect_cbor, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::UNKNOWN_ADDITIONAL_INFO); - } -} - -TEST(CBORReaderTest, TestTooMuchNestingError) { - static const std::vector kZeroDepthCBORList[] = { - // Unsigned int with value 100. - {0x18, 0x64}, - // CBOR bytestring of length 4. - {0x44, 0x01, 0x02, 0x03, 0x04}, - // CBOR string of corresponding to "IETF. - {0x64, 0x49, 0x45, 0x54, 0x46}, - // Empty CBOR array. - {0x80}, - // Empty CBOR Map - {0xa0}, - }; - - int test_element_index = 0; - for (const auto& zero_depth_data : kZeroDepthCBORList) { - SCOPED_TRACE(testing::Message() - << "testing zero nested data : " << test_element_index++); - CBORReader::DecoderError error_code; - base::Optional cbor = - CBORReader::Read(zero_depth_data, &error_code, 0); - EXPECT_TRUE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - } - - // Corresponds to a CBOR structure with a nesting depth of 2: - // {"a": 1, - // "b": [2, 3]} - static const std::vector kNestedCBORData = { - // clang-format off - 0xa2, // map of 2 pairs - 0x61, 0x61, // "a" - 0x01, - - 0x61, 0x62, // "b" - 0x82, // array with 2 elements - 0x02, - 0x03, - // clang-format on - }; - - CBORReader::DecoderError error_code; - base::Optional cbor_single_layer_max = - CBORReader::Read(kNestedCBORData, &error_code, 1); - EXPECT_FALSE(cbor_single_layer_max.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::TOO_MUCH_NESTING); - - base::Optional cbor_double_layer_max = - CBORReader::Read(kNestedCBORData, &error_code, 2); - EXPECT_TRUE(cbor_double_layer_max.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); -} - -TEST(CBORReaderTest, TestOutOfOrderKeyError) { - static const std::vector kMapsWithUnsortedKeys[] = { - // clang-format off - {0xa2, // map with 2 keys with same major type and length - 0x61, 0x62, // key "b" - 0x61, 0x42, // value "B" - - 0x61, 0x61, // key "a" (out of order byte-wise lexically) - 0x61, 0x45 // value "E" - }, - {0xa2, // map with 2 keys with different major type - 0x61, 0x62, // key "b" - 0x02, // value 2 - - // key 1000 (out of order since lower major type sorts first) - 0x19, 0x03, 0xe8, - 0x61, 0x61, // value a - }, - {0xa2, // map with 2 keys with same major type - 0x19, 0x03, 0xe8, // key 1000 (out of order due to longer length) - 0x61, 0x61, //value "a" - - 0x0a, // key 10 - 0x61, 0x62}, // value "b" - {0xa2, // map with 2 text string keys - 0x62, 'a', 'a', // key text string "aa" - // (out of order due to longer length) - 0x02, - - 0x61, 'b', // key "b" - 0x01, - }, - {0xa2, // map with 2 byte string keys - 0x42, 'x', 'x', // key byte string "xx" - // (out of order due to longer length) - 0x02, - - 0x41, 'y', // key byte string "y" - 0x01, - }, - //clang-format on - }; - - int test_element_index = 0; - CBORReader::DecoderError error_code; - for (const auto& unsorted_map : kMapsWithUnsortedKeys) { - testing::Message scope_message; - scope_message << "testing unsorted map : " << test_element_index++; - SCOPED_TRACE(scope_message); - - base::Optional cbor = - CBORReader::Read(unsorted_map, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_ORDER_KEY); - } -} - -TEST(CBORReaderTest, TestDuplicateKeyError) { - static const std::vector kMapWithDuplicateKey = { - // clang-format off - 0xa6, // map of 6 pairs: - 0x60, // "" - 0x61, 0x2e, // "." - - 0x61, 0x62, // "b" - 0x61, 0x42, // "B" - - 0x61, 0x62, // "b" (Duplicate key) - 0x61, 0x43, // "C" - - 0x61, 0x64, // "d" - 0x61, 0x44, // "D" - - 0x61, 0x65, // "e" - 0x61, 0x44, // "D" - - 0x62, 0x61, 0x61, // "aa" - 0x62, 0x41, 0x41, // "AA" - // clang-format on - }; - - CBORReader::DecoderError error_code; - - base::Optional cbor = - CBORReader::Read(kMapWithDuplicateKey, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_ORDER_KEY); -} - -// Leveraging Markus Kuhn’s UTF-8 decoder stress test. See -// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt for details. -TEST(CBORReaderTest, TestIncorrectStringEncodingError) { - static const std::vector utf8_character_encodings[] = { - // Corresponds to utf8 encoding of "퟿" (section 2.3.1 of stress test). - {0x63, 0xED, 0x9F, 0xBF}, - // Corresponds to utf8 encoding of "" (section 2.3.2 of stress test). - {0x63, 0xEE, 0x80, 0x80}, - // Corresponds to utf8 encoding of "�" (section 2.3.3 of stress test). - {0x63, 0xEF, 0xBF, 0xBD}, - }; - - int test_element_index = 0; - CBORReader::DecoderError error_code; - for (const auto& cbor_byte : utf8_character_encodings) { - SCOPED_TRACE(testing::Message() << "testing cbor data utf8 encoding : " - << test_element_index++); - - base::Optional correctly_encoded_cbor = - CBORReader::Read(cbor_byte, &error_code); - EXPECT_TRUE(correctly_encoded_cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR); - } - - // Incorrect UTF8 encoding referenced by section 3.5.3 of the stress test. - std::vector impossible_utf_byte{0x64, 0xfe, 0xfe, 0xff, 0xff}; - base::Optional incorrectly_encoded_cbor = - CBORReader::Read(impossible_utf_byte, &error_code); - EXPECT_FALSE(incorrectly_encoded_cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::INVALID_UTF8); -} - -TEST(CBORReaderTest, TestExtraneousCBORDataError) { - static const std::vector zero_padded_cbor_list[] = { - // 1 extra byte after a 2-byte unsigned int. - {0x19, 0x03, 0x05, 0x00}, - // 1 extra byte after a 4-byte cbor byte array. - {0x44, 0x01, 0x02, 0x03, 0x04, 0x00}, - // 1 extra byte after a 4-byte string. - {0x64, 0x49, 0x45, 0x54, 0x46, 0x00}, - // 1 extra byte after CBOR array of length 2. - {0x82, 0x01, 0x02, 0x00}, - // 1 extra key value pair after CBOR map of size 2. - {0xa1, 0x61, 0x63, 0x02, 0x61, 0x64, 0x03}, - }; - - int test_element_index = 0; - for (const auto& extraneous_cbor_data : zero_padded_cbor_list) { - SCOPED_TRACE(testing::Message() - << "testing cbor extraneous data : " << test_element_index++); - - CBORReader::DecoderError error_code; - base::Optional cbor = - CBORReader::Read(extraneous_cbor_data, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA); - } -} - -TEST(CBORReaderTest, TestUnsupportedSimpleValue) { - static const std::vector unsupported_simple_values[] = { - // Simple value (0, unassigned) - {0xE0}, - // Simple value (19, unassigned) - {0xF3}, - // Simple value (24, reserved) - {0xF8, 0x18}, - // Simple value (28, reserved) - {0xF8, 0x1C}, - // Simple value (29, reserved) - {0xF8, 0x1D}, - // Simple value (30, reserved) - {0xF8, 0x1E}, - // Simple value (31, reserved) - {0xF8, 0x1F}, - // Simple value (32, unassigned) - {0xF8, 0x20}, - // Simple value (255, unassigned) - {0xF8, 0xFF}, - }; - - for (const auto& unsupported_simple_val : unsupported_simple_values) { - SCOPED_TRACE(testing::Message() - << "testing unsupported cbor simple value : " - << ::testing::PrintToString(unsupported_simple_val)); - - CBORReader::DecoderError error_code; - base::Optional cbor = - CBORReader::Read(unsupported_simple_val, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::UNSUPPORTED_SIMPLE_VALUE); - } -} - -TEST(CBORReaderTest, TestSuperLongContentDontCrash) { - static const std::vector kTestCases[] = { - // CBOR array of 0xffffffff length. - {0x9b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - // CBOR map of 0xffffffff pairs. - {0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - }; - for (const auto& test_case : kTestCases) { - CBORReader::DecoderError error_code; - base::Optional cbor = CBORReader::Read(test_case, &error_code); - EXPECT_FALSE(cbor.has_value()); - EXPECT_EQ(error_code, CBORReader::DecoderError::INCOMPLETE_CBOR_DATA); - } -} - -} // namespace cbor diff --git a/chromium/components/cbor/cbor_values.cc b/chromium/components/cbor/cbor_values.cc deleted file mode 100644 index 397ce9a42c1..00000000000 --- a/chromium/components/cbor/cbor_values.cc +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/cbor/cbor_values.h" - -#include -#include - -#include "base/numerics/safe_conversions.h" -#include "base/strings/string_util.h" -#include "components/cbor/cbor_constants.h" - -namespace cbor { - -CBORValue::CBORValue() noexcept : type_(Type::NONE) {} - -CBORValue::CBORValue(CBORValue&& that) noexcept { - InternalMoveConstructFrom(std::move(that)); -} - -CBORValue::CBORValue(Type type) : type_(type) { - // Initialize with the default value. - switch (type_) { - case Type::UNSIGNED: - case Type::NEGATIVE: - integer_value_ = 0; - return; - case Type::BYTE_STRING: - new (&bytestring_value_) BinaryValue(); - return; - case Type::STRING: - new (&string_value_) std::string(); - return; - case Type::ARRAY: - new (&array_value_) ArrayValue(); - return; - case Type::MAP: - new (&map_value_) MapValue(); - return; - case Type::TAG: - NOTREACHED() << constants::kUnsupportedMajorType; - return; - case Type::SIMPLE_VALUE: - simple_value_ = CBORValue::SimpleValue::UNDEFINED; - return; - case Type::NONE: - return; - } - NOTREACHED(); -} - -CBORValue::CBORValue(SimpleValue in_simple) - : type_(Type::SIMPLE_VALUE), simple_value_(in_simple) { - CHECK(static_cast(in_simple) >= 20 && static_cast(in_simple) <= 23); -} - -CBORValue::CBORValue(bool boolean_value) : type_(Type::SIMPLE_VALUE) { - simple_value_ = boolean_value ? CBORValue::SimpleValue::TRUE_VALUE - : CBORValue::SimpleValue::FALSE_VALUE; -} - -CBORValue::CBORValue(int integer_value) - : CBORValue(base::checked_cast(integer_value)) {} - -CBORValue::CBORValue(int64_t integer_value) : integer_value_(integer_value) { - type_ = integer_value >= 0 ? Type::UNSIGNED : Type::NEGATIVE; -} - -CBORValue::CBORValue(base::span in_bytes) - : type_(Type::BYTE_STRING), - bytestring_value_(in_bytes.begin(), in_bytes.end()) {} - -CBORValue::CBORValue(BinaryValue&& in_bytes) noexcept - : type_(Type::BYTE_STRING), bytestring_value_(std::move(in_bytes)) {} - -CBORValue::CBORValue(const char* in_string, Type type) - : CBORValue(base::StringPiece(in_string), type) {} - -CBORValue::CBORValue(std::string&& in_string, Type type) noexcept - : type_(type) { - switch (type_) { - case Type::STRING: - new (&string_value_) std::string(); - string_value_ = std::move(in_string); - DCHECK(base::IsStringUTF8(string_value_)); - break; - case Type::BYTE_STRING: - new (&bytestring_value_) BinaryValue(); - bytestring_value_ = BinaryValue(in_string.begin(), in_string.end()); - break; - default: - NOTREACHED(); - } -} - -CBORValue::CBORValue(base::StringPiece in_string, Type type) : type_(type) { - switch (type_) { - case Type::STRING: - new (&string_value_) std::string(); - string_value_ = in_string.as_string(); - DCHECK(base::IsStringUTF8(string_value_)); - break; - case Type::BYTE_STRING: - new (&bytestring_value_) BinaryValue(); - bytestring_value_ = BinaryValue(in_string.begin(), in_string.end()); - break; - default: - NOTREACHED(); - } -} - -CBORValue::CBORValue(const ArrayValue& in_array) - : type_(Type::ARRAY), array_value_() { - array_value_.reserve(in_array.size()); - for (const auto& val : in_array) - array_value_.emplace_back(val.Clone()); -} - -CBORValue::CBORValue(ArrayValue&& in_array) noexcept - : type_(Type::ARRAY), array_value_(std::move(in_array)) {} - -CBORValue::CBORValue(const MapValue& in_map) : type_(Type::MAP), map_value_() { - map_value_.reserve(in_map.size()); - for (const auto& it : in_map) - map_value_.emplace_hint(map_value_.end(), it.first.Clone(), - it.second.Clone()); -} - -CBORValue::CBORValue(MapValue&& in_map) noexcept - : type_(Type::MAP), map_value_(std::move(in_map)) {} - -CBORValue& CBORValue::operator=(CBORValue&& that) noexcept { - InternalCleanup(); - InternalMoveConstructFrom(std::move(that)); - - return *this; -} - -CBORValue::~CBORValue() { - InternalCleanup(); -} - -CBORValue CBORValue::Clone() const { - switch (type_) { - case Type::NONE: - return CBORValue(); - case Type::UNSIGNED: - case Type::NEGATIVE: - return CBORValue(integer_value_); - case Type::BYTE_STRING: - return CBORValue(bytestring_value_); - case Type::STRING: - return CBORValue(string_value_); - case Type::ARRAY: - return CBORValue(array_value_); - case Type::MAP: - return CBORValue(map_value_); - case Type::TAG: - NOTREACHED() << constants::kUnsupportedMajorType; - return CBORValue(); - case Type::SIMPLE_VALUE: - return CBORValue(simple_value_); - } - - NOTREACHED(); - return CBORValue(); -} - -CBORValue::SimpleValue CBORValue::GetSimpleValue() const { - CHECK(is_simple()); - return simple_value_; -} - -bool CBORValue::GetBool() const { - CHECK(is_bool()); - return simple_value_ == SimpleValue::TRUE_VALUE; -} - -const int64_t& CBORValue::GetInteger() const { - CHECK(is_integer()); - return integer_value_; -} - -const int64_t& CBORValue::GetUnsigned() const { - CHECK(is_unsigned()); - CHECK_GE(integer_value_, 0); - return integer_value_; -} - -const int64_t& CBORValue::GetNegative() const { - CHECK(is_negative()); - CHECK_LT(integer_value_, 0); - return integer_value_; -} - -const std::string& CBORValue::GetString() const { - CHECK(is_string()); - return string_value_; -} - -const CBORValue::BinaryValue& CBORValue::GetBytestring() const { - CHECK(is_bytestring()); - return bytestring_value_; -} - -base::StringPiece CBORValue::GetBytestringAsString() const { - CHECK(is_bytestring()); - const auto& bytestring_value = GetBytestring(); - return base::StringPiece( - reinterpret_cast(bytestring_value.data()), - bytestring_value.size()); -} - -const CBORValue::ArrayValue& CBORValue::GetArray() const { - CHECK(is_array()); - return array_value_; -} - -const CBORValue::MapValue& CBORValue::GetMap() const { - CHECK(is_map()); - return map_value_; -} - -void CBORValue::InternalMoveConstructFrom(CBORValue&& that) { - type_ = that.type_; - - switch (type_) { - case Type::UNSIGNED: - case Type::NEGATIVE: - integer_value_ = that.integer_value_; - return; - case Type::BYTE_STRING: - new (&bytestring_value_) BinaryValue(std::move(that.bytestring_value_)); - return; - case Type::STRING: - new (&string_value_) std::string(std::move(that.string_value_)); - return; - case Type::ARRAY: - new (&array_value_) ArrayValue(std::move(that.array_value_)); - return; - case Type::MAP: - new (&map_value_) MapValue(std::move(that.map_value_)); - return; - case Type::TAG: - NOTREACHED() << constants::kUnsupportedMajorType; - return; - case Type::SIMPLE_VALUE: - simple_value_ = that.simple_value_; - return; - case Type::NONE: - return; - } - NOTREACHED(); -} - -void CBORValue::InternalCleanup() { - switch (type_) { - case Type::BYTE_STRING: - bytestring_value_.~BinaryValue(); - break; - case Type::STRING: - string_value_.~basic_string(); - break; - case Type::ARRAY: - array_value_.~ArrayValue(); - break; - case Type::MAP: - map_value_.~MapValue(); - break; - case Type::TAG: - NOTREACHED() << constants::kUnsupportedMajorType; - break; - case Type::NONE: - case Type::UNSIGNED: - case Type::NEGATIVE: - case Type::SIMPLE_VALUE: - break; - } - type_ = Type::NONE; -} - -} // namespace cbor diff --git a/chromium/components/cbor/cbor_values.h b/chromium/components/cbor/cbor_values.h deleted file mode 100644 index 39f2cca932b..00000000000 --- a/chromium/components/cbor/cbor_values.h +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_CBOR_CBOR_VALUES_H_ -#define COMPONENTS_CBOR_CBOR_VALUES_H_ - -#include - -#include -#include -#include - -#include "base/containers/flat_map.h" -#include "base/containers/span.h" -#include "base/macros.h" -#include "base/strings/string_piece.h" -#include "components/cbor/cbor_export.h" - -namespace cbor { - -// A class for Concise Binary Object Representation (CBOR) values. -// This does not support: -// * Floating-point numbers. -// * Indefinite-length encodings. -class CBOR_EXPORT CBORValue { - public: - struct Less { - // Comparison predicate to order keys in a dictionary as required by the - // canonical CBOR order defined in - // https://tools.ietf.org/html/rfc7049#section-3.9 - // TODO(808022): Clarify where this stands. - bool operator()(const CBORValue& a, const CBORValue& b) const { - // The current implementation only supports integer, text string, - // and byte string keys. - DCHECK((a.is_integer() || a.is_string() || a.is_bytestring()) && - (b.is_integer() || b.is_string() || b.is_bytestring())); - - // Below text from https://tools.ietf.org/html/rfc7049 errata 4409: - // * If the major types are different, the one with the lower value - // in numerical order sorts earlier. - if (a.type() != b.type()) - return a.type() < b.type(); - - // * If two keys have different lengths, the shorter one sorts - // earlier; - // * If two keys have the same length, the one with the lower value - // in (byte-wise) lexical order sorts earlier. - switch (a.type()) { - case Type::UNSIGNED: - // For unsigned integers, the smaller value has shorter length, - // and (byte-wise) lexical representation. - return a.GetInteger() < b.GetInteger(); - case Type::NEGATIVE: - // For negative integers, the value closer to zero has shorter length, - // and (byte-wise) lexical representation. - return a.GetInteger() > b.GetInteger(); - case Type::STRING: { - const auto& a_str = a.GetString(); - const size_t a_length = a_str.size(); - const auto& b_str = b.GetString(); - const size_t b_length = b_str.size(); - return std::tie(a_length, a_str) < std::tie(b_length, b_str); - } - case Type::BYTE_STRING: { - const auto& a_str = a.GetBytestring(); - const size_t a_length = a_str.size(); - const auto& b_str = b.GetBytestring(); - const size_t b_length = b_str.size(); - return std::tie(a_length, a_str) < std::tie(b_length, b_str); - } - default: - break; - } - - NOTREACHED(); - return false; - } - - using is_transparent = void; - }; - - using BinaryValue = std::vector; - using ArrayValue = std::vector; - using MapValue = base::flat_map; - - enum class Type { - UNSIGNED = 0, - NEGATIVE = 1, - BYTE_STRING = 2, - STRING = 3, - ARRAY = 4, - MAP = 5, - TAG = 6, - SIMPLE_VALUE = 7, - NONE = -1, - }; - - enum class SimpleValue { - FALSE_VALUE = 20, - TRUE_VALUE = 21, - NULL_VALUE = 22, - UNDEFINED = 23, - }; - - CBORValue(CBORValue&& that) noexcept; - CBORValue() noexcept; // A NONE value. - - explicit CBORValue(Type type); - - explicit CBORValue(SimpleValue in_simple); - explicit CBORValue(bool boolean_value); - - explicit CBORValue(int integer_value); - explicit CBORValue(int64_t integer_value); - explicit CBORValue(uint64_t integer_value) = delete; - - explicit CBORValue(base::span in_bytes); - explicit CBORValue(BinaryValue&& in_bytes) noexcept; - - explicit CBORValue(const char* in_string, Type type = Type::STRING); - explicit CBORValue(std::string&& in_string, - Type type = Type::STRING) noexcept; - explicit CBORValue(base::StringPiece in_string, Type type = Type::STRING); - - explicit CBORValue(const ArrayValue& in_array); - explicit CBORValue(ArrayValue&& in_array) noexcept; - - explicit CBORValue(const MapValue& in_map); - explicit CBORValue(MapValue&& in_map) noexcept; - - CBORValue& operator=(CBORValue&& that) noexcept; - - ~CBORValue(); - - // CBORValue's copy constructor and copy assignment operator are deleted. - // Use this to obtain a deep copy explicitly. - CBORValue Clone() const; - - // Returns the type of the value stored by the current Value object. - Type type() const { return type_; } - - // Returns true if the current object represents a given type. - bool is_type(Type type) const { return type == type_; } - bool is_none() const { return type() == Type::NONE; } - bool is_simple() const { return type() == Type::SIMPLE_VALUE; } - bool is_bool() const { - return is_simple() && (simple_value_ == SimpleValue::TRUE_VALUE || - simple_value_ == SimpleValue::FALSE_VALUE); - } - bool is_unsigned() const { return type() == Type::UNSIGNED; } - bool is_negative() const { return type() == Type::NEGATIVE; } - bool is_integer() const { return is_unsigned() || is_negative(); } - bool is_bytestring() const { return type() == Type::BYTE_STRING; } - bool is_string() const { return type() == Type::STRING; } - bool is_array() const { return type() == Type::ARRAY; } - bool is_map() const { return type() == Type::MAP; } - - // These will all fatally assert if the type doesn't match. - SimpleValue GetSimpleValue() const; - bool GetBool() const; - const int64_t& GetInteger() const; - const int64_t& GetUnsigned() const; - const int64_t& GetNegative() const; - const BinaryValue& GetBytestring() const; - base::StringPiece GetBytestringAsString() const; - // Returned string may contain NUL characters. - const std::string& GetString() const; - const ArrayValue& GetArray() const; - const MapValue& GetMap() const; - - private: - Type type_; - - union { - SimpleValue simple_value_; - int64_t integer_value_; - BinaryValue bytestring_value_; - std::string string_value_; - ArrayValue array_value_; - MapValue map_value_; - }; - - void InternalMoveConstructFrom(CBORValue&& that); - void InternalCleanup(); - - DISALLOW_COPY_AND_ASSIGN(CBORValue); -}; -} // namespace cbor - -#endif // COMPONENTS_CBOR_CBOR_VALUES_H_ diff --git a/chromium/components/cbor/cbor_values_unittest.cc b/chromium/components/cbor/cbor_values_unittest.cc deleted file mode 100644 index 23a959ece17..00000000000 --- a/chromium/components/cbor/cbor_values_unittest.cc +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/cbor/cbor_values.h" - -#include -#include - -#include "testing/gtest/include/gtest/gtest.h" - -namespace cbor { - -TEST(CBORValuesTest, TestNothrow) { - static_assert(std::is_nothrow_move_constructible::value, - "IsNothrowMoveConstructible"); - static_assert(std::is_nothrow_default_constructible::value, - "IsNothrowDefaultConstructible"); - static_assert(std::is_nothrow_constructible::value, - "IsNothrowMoveConstructibleFromString"); - static_assert( - std::is_nothrow_constructible::value, - "IsNothrowMoveConstructibleFromBytestring"); - static_assert( - std::is_nothrow_constructible::value, - "IsNothrowMoveConstructibleFromArray"); - static_assert(std::is_nothrow_move_assignable::value, - "IsNothrowMoveAssignable"); -} - -// Test constructors -TEST(CBORValuesTest, ConstructUnsigned) { - CBORValue value(37); - ASSERT_EQ(CBORValue::Type::UNSIGNED, value.type()); - EXPECT_EQ(37u, value.GetInteger()); -} - -TEST(CBORValuesTest, ConstructNegative) { - CBORValue value(-1); - ASSERT_EQ(CBORValue::Type::NEGATIVE, value.type()); - EXPECT_EQ(-1, value.GetInteger()); -} - -TEST(CBORValuesTest, ConstructStringFromConstCharPtr) { - const char* str = "foobar"; - CBORValue value(str); - ASSERT_EQ(CBORValue::Type::STRING, value.type()); - EXPECT_EQ("foobar", value.GetString()); -} - -TEST(CBORValuesTest, ConstructStringFromStdStringConstRef) { - std::string str = "foobar"; - CBORValue value(str); - ASSERT_EQ(CBORValue::Type::STRING, value.type()); - EXPECT_EQ("foobar", value.GetString()); -} - -TEST(CBORValuesTest, ConstructStringFromStdStringRefRef) { - std::string str = "foobar"; - CBORValue value(std::move(str)); - ASSERT_EQ(CBORValue::Type::STRING, value.type()); - EXPECT_EQ("foobar", value.GetString()); -} - -TEST(CBORValuesTest, ConstructBytestring) { - CBORValue value(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2})); - ASSERT_EQ(CBORValue::Type::BYTE_STRING, value.type()); - EXPECT_EQ(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}), - value.GetBytestring()); -} - -TEST(CBORValuesTest, ConstructBytestringFromString) { - CBORValue value(CBORValue("hello", CBORValue::Type::BYTE_STRING)); - ASSERT_EQ(CBORValue::Type::BYTE_STRING, value.type()); - EXPECT_EQ(CBORValue::BinaryValue({'h', 'e', 'l', 'l', 'o'}), - value.GetBytestring()); - EXPECT_EQ("hello", value.GetBytestringAsString()); -} - -TEST(CBORValuesTest, ConstructArray) { - CBORValue::ArrayValue array; - array.emplace_back(CBORValue("foo")); - { - CBORValue value(array); - ASSERT_EQ(CBORValue::Type::ARRAY, value.type()); - ASSERT_EQ(1u, value.GetArray().size()); - ASSERT_EQ(CBORValue::Type::STRING, value.GetArray()[0].type()); - EXPECT_EQ("foo", value.GetArray()[0].GetString()); - } - - array.back() = CBORValue("bar"); - { - CBORValue value(std::move(array)); - ASSERT_EQ(CBORValue::Type::ARRAY, value.type()); - ASSERT_EQ(1u, value.GetArray().size()); - ASSERT_EQ(CBORValue::Type::STRING, value.GetArray()[0].type()); - EXPECT_EQ("bar", value.GetArray()[0].GetString()); - } -} - -TEST(CBORValuesTest, ConstructMap) { - CBORValue::MapValue map; - const CBORValue key_foo("foo"); - map[CBORValue("foo")] = CBORValue("bar"); - { - CBORValue value(map); - ASSERT_EQ(CBORValue::Type::MAP, value.type()); - ASSERT_EQ(value.GetMap().count(key_foo), 1u); - ASSERT_EQ(CBORValue::Type::STRING, - value.GetMap().find(key_foo)->second.type()); - EXPECT_EQ("bar", value.GetMap().find(key_foo)->second.GetString()); - } - - map[CBORValue("foo")] = CBORValue("baz"); - { - CBORValue value(std::move(map)); - ASSERT_EQ(CBORValue::Type::MAP, value.type()); - ASSERT_EQ(value.GetMap().count(key_foo), 1u); - ASSERT_EQ(CBORValue::Type::STRING, - value.GetMap().find(key_foo)->second.type()); - EXPECT_EQ("baz", value.GetMap().find(key_foo)->second.GetString()); - } -} - -TEST(CBORValuesTest, ConstructSimpleValue) { - CBORValue false_value(CBORValue::SimpleValue::FALSE_VALUE); - ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, false_value.type()); - EXPECT_EQ(CBORValue::SimpleValue::FALSE_VALUE, false_value.GetSimpleValue()); - - CBORValue true_value(CBORValue::SimpleValue::TRUE_VALUE); - ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, true_value.type()); - EXPECT_EQ(CBORValue::SimpleValue::TRUE_VALUE, true_value.GetSimpleValue()); - - CBORValue null_value(CBORValue::SimpleValue::NULL_VALUE); - ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, null_value.type()); - EXPECT_EQ(CBORValue::SimpleValue::NULL_VALUE, null_value.GetSimpleValue()); - - CBORValue undefined_value(CBORValue::SimpleValue::UNDEFINED); - ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, undefined_value.type()); - EXPECT_EQ(CBORValue::SimpleValue::UNDEFINED, - undefined_value.GetSimpleValue()); -} - -TEST(CBORValuesTest, ConstructSimpleBooleanValue) { - CBORValue true_value(true); - ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, true_value.type()); - EXPECT_TRUE(true_value.GetBool()); - - CBORValue false_value(false); - ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, false_value.type()); - EXPECT_FALSE(false_value.GetBool()); -} - -// Test copy constructors -TEST(CBORValuesTest, CopyUnsigned) { - CBORValue value(74); - CBORValue copied_value(value.Clone()); - ASSERT_EQ(value.type(), copied_value.type()); - EXPECT_EQ(value.GetInteger(), copied_value.GetInteger()); - - CBORValue blank; - - blank = value.Clone(); - ASSERT_EQ(value.type(), blank.type()); - EXPECT_EQ(value.GetInteger(), blank.GetInteger()); -} - -TEST(CBORValuesTest, CopyNegativeInt) { - CBORValue value(-74); - CBORValue copied_value(value.Clone()); - ASSERT_EQ(value.type(), copied_value.type()); - EXPECT_EQ(value.GetInteger(), copied_value.GetInteger()); - - CBORValue blank; - - blank = value.Clone(); - ASSERT_EQ(value.type(), blank.type()); - EXPECT_EQ(value.GetInteger(), blank.GetInteger()); -} - -TEST(CBORValuesTest, CopyString) { - CBORValue value("foobar"); - CBORValue copied_value(value.Clone()); - ASSERT_EQ(value.type(), copied_value.type()); - EXPECT_EQ(value.GetString(), copied_value.GetString()); - - CBORValue blank; - - blank = value.Clone(); - ASSERT_EQ(value.type(), blank.type()); - EXPECT_EQ(value.GetString(), blank.GetString()); -} - -TEST(CBORValuesTest, CopyBytestring) { - CBORValue value(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2})); - CBORValue copied_value(value.Clone()); - ASSERT_EQ(value.type(), copied_value.type()); - EXPECT_EQ(value.GetBytestring(), copied_value.GetBytestring()); - - CBORValue blank; - - blank = value.Clone(); - ASSERT_EQ(value.type(), blank.type()); - EXPECT_EQ(value.GetBytestring(), blank.GetBytestring()); -} - -TEST(CBORValuesTest, CopyArray) { - CBORValue::ArrayValue array; - array.emplace_back(123); - CBORValue value(std::move(array)); - - CBORValue copied_value(value.Clone()); - ASSERT_EQ(1u, copied_value.GetArray().size()); - ASSERT_TRUE(copied_value.GetArray()[0].is_unsigned()); - EXPECT_EQ(value.GetArray()[0].GetInteger(), - copied_value.GetArray()[0].GetInteger()); - - CBORValue blank; - blank = value.Clone(); - EXPECT_EQ(1u, blank.GetArray().size()); -} - -TEST(CBORValuesTest, CopyMap) { - CBORValue::MapValue map; - CBORValue key_a("a"); - map[CBORValue("a")] = CBORValue(123); - CBORValue value(std::move(map)); - - CBORValue copied_value(value.Clone()); - EXPECT_EQ(1u, copied_value.GetMap().size()); - ASSERT_EQ(value.GetMap().count(key_a), 1u); - ASSERT_EQ(copied_value.GetMap().count(key_a), 1u); - ASSERT_TRUE(copied_value.GetMap().find(key_a)->second.is_unsigned()); - EXPECT_EQ(value.GetMap().find(key_a)->second.GetInteger(), - copied_value.GetMap().find(key_a)->second.GetInteger()); - - CBORValue blank; - blank = value.Clone(); - EXPECT_EQ(1u, blank.GetMap().size()); - ASSERT_EQ(blank.GetMap().count(key_a), 1u); - ASSERT_TRUE(blank.GetMap().find(key_a)->second.is_unsigned()); - EXPECT_EQ(value.GetMap().find(key_a)->second.GetInteger(), - blank.GetMap().find(key_a)->second.GetInteger()); -} - -TEST(CBORValuesTest, CopySimpleValue) { - CBORValue value(CBORValue::SimpleValue::TRUE_VALUE); - CBORValue copied_value(value.Clone()); - EXPECT_EQ(value.type(), copied_value.type()); - EXPECT_EQ(value.GetSimpleValue(), copied_value.GetSimpleValue()); - - CBORValue blank; - - blank = value.Clone(); - EXPECT_EQ(value.type(), blank.type()); - EXPECT_EQ(value.GetSimpleValue(), blank.GetSimpleValue()); -} - -// Test move constructors and move-assignment -TEST(CBORValuesTest, MoveUnsigned) { - CBORValue value(74); - CBORValue moved_value(std::move(value)); - EXPECT_EQ(CBORValue::Type::UNSIGNED, moved_value.type()); - EXPECT_EQ(74u, moved_value.GetInteger()); - - CBORValue blank; - - blank = CBORValue(654); - EXPECT_EQ(CBORValue::Type::UNSIGNED, blank.type()); - EXPECT_EQ(654u, blank.GetInteger()); -} - -TEST(CBORValuesTest, MoveNegativeInteger) { - CBORValue value(-74); - CBORValue moved_value(std::move(value)); - EXPECT_EQ(CBORValue::Type::NEGATIVE, moved_value.type()); - EXPECT_EQ(-74, moved_value.GetInteger()); - - CBORValue blank; - - blank = CBORValue(-654); - EXPECT_EQ(CBORValue::Type::NEGATIVE, blank.type()); - EXPECT_EQ(-654, blank.GetInteger()); -} - -TEST(CBORValuesTest, MoveString) { - CBORValue value("foobar"); - CBORValue moved_value(std::move(value)); - EXPECT_EQ(CBORValue::Type::STRING, moved_value.type()); - EXPECT_EQ("foobar", moved_value.GetString()); - - CBORValue blank; - - blank = CBORValue("foobar"); - EXPECT_EQ(CBORValue::Type::STRING, blank.type()); - EXPECT_EQ("foobar", blank.GetString()); -} - -TEST(CBORValuesTest, MoveBytestring) { - const CBORValue::BinaryValue bytes({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}); - CBORValue value(bytes); - CBORValue moved_value(std::move(value)); - EXPECT_EQ(CBORValue::Type::BYTE_STRING, moved_value.type()); - EXPECT_EQ(bytes, moved_value.GetBytestring()); - - CBORValue blank; - - blank = CBORValue(bytes); - EXPECT_EQ(CBORValue::Type::BYTE_STRING, blank.type()); - EXPECT_EQ(bytes, blank.GetBytestring()); -} - -TEST(CBORValuesTest, MoveConstructMap) { - CBORValue::MapValue map; - const CBORValue key_a("a"); - map[CBORValue("a")] = CBORValue(123); - - CBORValue value(std::move(map)); - CBORValue moved_value(std::move(value)); - ASSERT_EQ(CBORValue::Type::MAP, moved_value.type()); - ASSERT_EQ(moved_value.GetMap().count(key_a), 1u); - ASSERT_TRUE(moved_value.GetMap().find(key_a)->second.is_unsigned()); - EXPECT_EQ(123u, moved_value.GetMap().find(key_a)->second.GetInteger()); -} - -TEST(CBORValuesTest, MoveAssignMap) { - CBORValue::MapValue map; - const CBORValue key_a("a"); - map[CBORValue("a")] = CBORValue(123); - - CBORValue blank; - blank = CBORValue(std::move(map)); - ASSERT_TRUE(blank.is_map()); - ASSERT_EQ(blank.GetMap().count(key_a), 1u); - ASSERT_TRUE(blank.GetMap().find(key_a)->second.is_unsigned()); - EXPECT_EQ(123u, blank.GetMap().find(key_a)->second.GetInteger()); -} - -TEST(CBORValuesTest, MoveArray) { - CBORValue::ArrayValue array; - array.emplace_back(123); - CBORValue value(array); - CBORValue moved_value(std::move(value)); - EXPECT_EQ(CBORValue::Type::ARRAY, moved_value.type()); - EXPECT_EQ(123u, moved_value.GetArray().back().GetInteger()); - - CBORValue blank; - blank = CBORValue(std::move(array)); - EXPECT_EQ(CBORValue::Type::ARRAY, blank.type()); - EXPECT_EQ(123u, blank.GetArray().back().GetInteger()); -} - -TEST(CBORValuesTest, MoveSimpleValue) { - CBORValue value(CBORValue::SimpleValue::UNDEFINED); - CBORValue moved_value(std::move(value)); - EXPECT_EQ(CBORValue::Type::SIMPLE_VALUE, moved_value.type()); - EXPECT_EQ(CBORValue::SimpleValue::UNDEFINED, moved_value.GetSimpleValue()); - - CBORValue blank; - - blank = CBORValue(CBORValue::SimpleValue::UNDEFINED); - EXPECT_EQ(CBORValue::Type::SIMPLE_VALUE, blank.type()); - EXPECT_EQ(CBORValue::SimpleValue::UNDEFINED, blank.GetSimpleValue()); -} - -TEST(CBORValuesTest, SelfSwap) { - CBORValue test(1); - std::swap(test, test); - EXPECT_EQ(test.GetInteger(), 1u); -} - -} // namespace cbor diff --git a/chromium/components/cbor/cbor_writer.cc b/chromium/components/cbor/cbor_writer.cc deleted file mode 100644 index 5312ab9357f..00000000000 --- a/chromium/components/cbor/cbor_writer.cc +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/cbor/cbor_writer.h" - -#include - -#include "base/numerics/safe_conversions.h" -#include "base/strings/string_piece.h" -#include "components/cbor/cbor_constants.h" - -namespace cbor { - -CBORWriter::~CBORWriter() {} - -// static -base::Optional> CBORWriter::Write( - const CBORValue& node, - size_t max_nesting_level) { - std::vector cbor; - CBORWriter writer(&cbor); - if (writer.EncodeCBOR(node, base::checked_cast(max_nesting_level))) - return cbor; - return base::nullopt; -} - -CBORWriter::CBORWriter(std::vector* cbor) : encoded_cbor_(cbor) {} - -bool CBORWriter::EncodeCBOR(const CBORValue& node, int max_nesting_level) { - if (max_nesting_level < 0) - return false; - - switch (node.type()) { - case CBORValue::Type::NONE: { - StartItem(CBORValue::Type::BYTE_STRING, 0); - return true; - } - - // Represents unsigned integers. - case CBORValue::Type::UNSIGNED: { - int64_t value = node.GetUnsigned(); - StartItem(CBORValue::Type::UNSIGNED, static_cast(value)); - return true; - } - - // Represents negative integers. - case CBORValue::Type::NEGATIVE: { - int64_t value = node.GetNegative(); - StartItem(CBORValue::Type::NEGATIVE, static_cast(-(value + 1))); - return true; - } - - // Represents a byte string. - case CBORValue::Type::BYTE_STRING: { - const CBORValue::BinaryValue& bytes = node.GetBytestring(); - StartItem(CBORValue::Type::BYTE_STRING, - base::strict_cast(bytes.size())); - // Add the bytes. - encoded_cbor_->insert(encoded_cbor_->end(), bytes.begin(), bytes.end()); - return true; - } - - case CBORValue::Type::STRING: { - base::StringPiece string = node.GetString(); - StartItem(CBORValue::Type::STRING, - base::strict_cast(string.size())); - - // Add the characters. - encoded_cbor_->insert(encoded_cbor_->end(), string.begin(), string.end()); - return true; - } - - // Represents an array. - case CBORValue::Type::ARRAY: { - const CBORValue::ArrayValue& array = node.GetArray(); - StartItem(CBORValue::Type::ARRAY, array.size()); - for (const auto& value : array) { - if (!EncodeCBOR(value, max_nesting_level - 1)) - return false; - } - return true; - } - - // Represents a map. - case CBORValue::Type::MAP: { - const CBORValue::MapValue& map = node.GetMap(); - StartItem(CBORValue::Type::MAP, map.size()); - - for (const auto& value : map) { - if (!EncodeCBOR(value.first, max_nesting_level - 1)) - return false; - if (!EncodeCBOR(value.second, max_nesting_level - 1)) - return false; - } - return true; - } - - case CBORValue::Type::TAG: - NOTREACHED() << constants::kUnsupportedMajorType; - return false; - - // Represents a simple value. - case CBORValue::Type::SIMPLE_VALUE: { - const CBORValue::SimpleValue simple_value = node.GetSimpleValue(); - StartItem(CBORValue::Type::SIMPLE_VALUE, - base::checked_cast(simple_value)); - return true; - } - } - - // This is needed because, otherwise, MSVC complains that not all paths return - // a value. We should be able to remove it once MSVC builders are gone. - NOTREACHED(); - return false; -} - -void CBORWriter::StartItem(CBORValue::Type type, uint64_t size) { - encoded_cbor_->push_back(base::checked_cast( - static_cast(type) << constants::kMajorTypeBitShift)); - SetUint(size); -} - -void CBORWriter::SetAdditionalInformation(uint8_t additional_information) { - DCHECK(!encoded_cbor_->empty()); - DCHECK_EQ(additional_information & constants::kAdditionalInformationMask, - additional_information); - encoded_cbor_->back() |= - (additional_information & constants::kAdditionalInformationMask); -} - -void CBORWriter::SetUint(uint64_t value) { - size_t count = GetNumUintBytes(value); - int shift = -1; - // Values under 24 are encoded directly in the initial byte. - // Otherwise, the last 5 bits of the initial byte contains the length - // of unsigned integer, which is encoded in following bytes. - switch (count) { - case 0: - SetAdditionalInformation(base::checked_cast(value)); - break; - case 1: - SetAdditionalInformation(constants::kAdditionalInformation1Byte); - shift = 0; - break; - case 2: - SetAdditionalInformation(constants::kAdditionalInformation2Bytes); - shift = 1; - break; - case 4: - SetAdditionalInformation(constants::kAdditionalInformation4Bytes); - shift = 3; - break; - case 8: - SetAdditionalInformation(constants::kAdditionalInformation8Bytes); - shift = 7; - break; - default: - NOTREACHED(); - break; - } - for (; shift >= 0; shift--) { - encoded_cbor_->push_back(0xFF & (value >> (shift * 8))); - } -} - -size_t CBORWriter::GetNumUintBytes(uint64_t value) { - if (value < 24) { - return 0; - } else if (value <= 0xFF) { - return 1; - } else if (value <= 0xFFFF) { - return 2; - } else if (value <= 0xFFFFFFFF) { - return 4; - } - return 8; -} - -} // namespace cbor diff --git a/chromium/components/cbor/cbor_writer.h b/chromium/components/cbor/cbor_writer.h deleted file mode 100644 index 89e24da742e..00000000000 --- a/chromium/components/cbor/cbor_writer.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_CBOR_CBOR_WRITER_H_ -#define COMPONENTS_CBOR_CBOR_WRITER_H_ - -#include -#include -#include - -#include "base/optional.h" -#include "components/cbor/cbor_export.h" -#include "components/cbor/cbor_values.h" - -// A basic Concise Binary Object Representation (CBOR) encoder as defined by -// https://tools.ietf.org/html/rfc7049. This is a generic encoder that supplies -// canonical, well-formed CBOR values but does not guarantee their validity -// (see https://tools.ietf.org/html/rfc7049#section-3.2). -// Supported: -// * Major types: -// * 0: Unsigned integers, up to INT64_MAX. -// * 1: Negative integers, to INT64_MIN. -// * 2: Byte strings. -// * 3: UTF-8 strings. -// * 4: Arrays, with the number of elements known at the start. -// * 5: Maps, with the number of elements known at the start -// of the container. -// * 7: Simple values. -// -// Unsupported: -// * Floating-point numbers. -// * Indefinite-length encodings. -// * Parsing. -// -// Requirements for canonical CBOR as suggested by RFC 7049 are: -// 1) All major data types for the CBOR values must be as short as possible. -// * Unsigned integer between 0 to 23 must be expressed in same byte as -// the major type. -// * 24 to 255 must be expressed only with an additional uint8_t. -// * 256 to 65535 must be expressed only with an additional uint16_t. -// * 65536 to 4294967295 must be expressed only with an additional -// uint32_t. * The rules for expression of length in major types -// 2 to 5 follow the above rule for integers. -// 2) Keys in every map must be sorted (first by major type, then by key -// length, then by value in byte-wise lexical order). -// 3) Indefinite length items must be converted to definite length items. -// 4) All maps must not have duplicate keys. -// -// Current implementation of CBORWriter encoder meets all the requirements of -// canonical CBOR. - -namespace cbor { - -class CBOR_EXPORT CBORWriter { - public: - // Default that should be sufficiently large for most use cases. - static constexpr size_t kDefaultMaxNestingDepth = 16; - - ~CBORWriter(); - - // Returns the CBOR byte string representation of |node|, unless its nesting - // depth is greater than |max_nesting_depth|, in which case an empty optional - // value is returned. The nesting depth of |node| is defined as the number of - // arrays/maps that has to be traversed to reach the most nested CBORValue - // contained in |node|. Primitive values and empty containers have nesting - // depths of 0. - static base::Optional> Write( - const CBORValue& node, - size_t max_nesting_level = kDefaultMaxNestingDepth); - - private: - explicit CBORWriter(std::vector* cbor); - - // Called recursively to build the CBOR bytestring. When completed, - // |encoded_cbor_| will contain the CBOR. - bool EncodeCBOR(const CBORValue& node, int max_nesting_level); - - // Encodes the type and size of the data being added. - void StartItem(CBORValue::Type type, uint64_t size); - - // Encodes the additional information for the data. - void SetAdditionalInformation(uint8_t additional_information); - - // Encodes an unsigned integer value. This is used to both write - // unsigned integers and to encode the lengths of other major types. - void SetUint(uint64_t value); - - // Get the number of bytes needed to store the unsigned integer. - size_t GetNumUintBytes(uint64_t value); - - // Holds the encoded CBOR data. - std::vector* encoded_cbor_; - - DISALLOW_COPY_AND_ASSIGN(CBORWriter); -}; - -} // namespace cbor - -#endif // COMPONENTS_CBOR_CBOR_WRITER_H_ diff --git a/chromium/components/cbor/cbor_writer_unittest.cc b/chromium/components/cbor/cbor_writer_unittest.cc deleted file mode 100644 index 955a19b8104..00000000000 --- a/chromium/components/cbor/cbor_writer_unittest.cc +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/cbor/cbor_writer.h" - -#include -#include - -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -/* Leveraging RFC 7049 examples from - https://github.com/cbor/test-vectors/blob/master/appendix_a.json. */ -namespace cbor { - -TEST(CBORWriterTest, TestWriteUint) { - typedef struct { - const int64_t value; - const base::StringPiece cbor; - } UintTestCase; - - static const UintTestCase kUintTestCases[] = { - // Reminder: must specify length when creating string pieces - // with null bytes, else the string will truncate prematurely. - {0, base::StringPiece("\x00", 1)}, - {1, base::StringPiece("\x01")}, - {10, base::StringPiece("\x0a")}, - {23, base::StringPiece("\x17")}, - {24, base::StringPiece("\x18\x18")}, - {25, base::StringPiece("\x18\x19")}, - {100, base::StringPiece("\x18\x64")}, - {1000, base::StringPiece("\x19\x03\xe8")}, - {1000000, base::StringPiece("\x1a\x00\x0f\x42\x40", 5)}, - {0xFFFFFFFF, base::StringPiece("\x1a\xff\xff\xff\xff")}, - {0x100000000, - base::StringPiece("\x1b\x00\x00\x00\x01\x00\x00\x00\x00", 9)}, - {std::numeric_limits::max(), - base::StringPiece("\x1b\x7f\xff\xff\xff\xff\xff\xff\xff")}}; - - for (const UintTestCase& test_case : kUintTestCases) { - auto cbor = CBORWriter::Write(CBORValue(test_case.value)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); - } -} - -TEST(CBORWriterTest, TestWriteNegativeInteger) { - static const struct { - const int64_t negative_int; - const base::StringPiece cbor; - } kNegativeIntTestCases[] = { - {-1LL, base::StringPiece("\x20")}, - {-10LL, base::StringPiece("\x29")}, - {-23LL, base::StringPiece("\x36")}, - {-24LL, base::StringPiece("\x37")}, - {-25LL, base::StringPiece("\x38\x18")}, - {-100LL, base::StringPiece("\x38\x63")}, - {-1000LL, base::StringPiece("\x39\x03\xe7")}, - {-4294967296LL, base::StringPiece("\x3a\xff\xff\xff\xff")}, - {-4294967297LL, - base::StringPiece("\x3b\x00\x00\x00\x01\x00\x00\x00\x00", 9)}, - {std::numeric_limits::min(), - base::StringPiece("\x3b\x7f\xff\xff\xff\xff\xff\xff\xff")}, - }; - - for (const auto& test_case : kNegativeIntTestCases) { - SCOPED_TRACE(testing::Message() << "testing negative int at index: " - << test_case.negative_int); - - auto cbor = CBORWriter::Write(CBORValue(test_case.negative_int)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); - } -} - -TEST(CBORWriterTest, TestWriteBytes) { - typedef struct { - const std::vector bytes; - const base::StringPiece cbor; - } BytesTestCase; - - static const BytesTestCase kBytesTestCases[] = { - {{}, base::StringPiece("\x40")}, - {{0x01, 0x02, 0x03, 0x04}, base::StringPiece("\x44\x01\x02\x03\x04")}, - }; - - for (const BytesTestCase& test_case : kBytesTestCases) { - auto cbor = CBORWriter::Write(CBORValue(test_case.bytes)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); - } -} - -TEST(CBORWriterTest, TestWriteString) { - typedef struct { - const std::string string; - const base::StringPiece cbor; - } StringTestCase; - - static const StringTestCase kStringTestCases[] = { - {"", base::StringPiece("\x60")}, - {"a", base::StringPiece("\x61\x61")}, - {"IETF", base::StringPiece("\x64\x49\x45\x54\x46")}, - {"\"\\", base::StringPiece("\x62\x22\x5c")}, - {"\xc3\xbc", base::StringPiece("\x62\xc3\xbc")}, - {"\xe6\xb0\xb4", base::StringPiece("\x63\xe6\xb0\xb4")}, - {"\xf0\x90\x85\x91", base::StringPiece("\x64\xf0\x90\x85\x91")}}; - - for (const StringTestCase& test_case : kStringTestCases) { - SCOPED_TRACE(testing::Message() - << "testing encoding string : " << test_case.string); - - auto cbor = CBORWriter::Write(CBORValue(test_case.string)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); - } -} - -TEST(CBORWriterTest, TestWriteArray) { - static const uint8_t kArrayTestCaseCbor[] = { - // clang-format off - 0x98, 0x19, // array of 25 elements - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, - 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x18, 0x18, 0x19, - // clang-format on - }; - std::vector array; - for (int64_t i = 1; i <= 25; i++) { - array.push_back(CBORValue(i)); - } - auto cbor = CBORWriter::Write(CBORValue(array)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), - testing::ElementsAreArray(kArrayTestCaseCbor, - arraysize(kArrayTestCaseCbor))); -} - -TEST(CBORWriterTest, TestWriteMap) { - static const uint8_t kMapTestCaseCbor[] = { - // clang-format off - 0xb8, 0x19, // map of 25 pairs: - 0x00, // key 0 - 0x61, 0x61, // value "a" - - 0x17, // key 23 - 0x61, 0x62, // value "b" - - 0x18, 0x18, // key 24 - 0x61, 0x63, // value "c" - - 0x18, 0xFF, // key 255 - 0x61, 0x64, // value "d" - - 0x19, 0x01, 0x00, // key 256 - 0x61, 0x65, // value "e" - - 0x19, 0xFF, 0xFF, // key 65535 - 0x61, 0x66, // value "f" - - 0x1A, 0x00, 0x01, 0x00, 0x00, // key 65536 - 0x61, 0x67, // value "g" - - 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, // key 4294967295 - 0x61, 0x68, // value "h" - - // key 4294967296 - 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x69, // value "i" - - // key INT64_MAX - 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x61, 0x6a, // value "j" - - 0x20, // key -1 - 0x61, 0x6b, // value "k" - - 0x37, // key -24 - 0x61, 0x6c, // value "l" - - 0x38, 0x18, // key -25 - 0x61, 0x6d, // value "m" - - 0x38, 0xFF, // key -256 - 0x61, 0x6e, // value "n" - - 0x39, 0x01, 0x00, // key -257 - 0x61, 0x6f, // value "o" - - 0x3A, 0x00, 0x01, 0x00, 0x00, // key -65537 - 0x61, 0x70, // value "p" - - 0x3A, 0xFF, 0xFF, 0xFF, 0xFF, // key -4294967296 - 0x61, 0x71, // value "q" - - // key -4294967297 - 0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x72, // value "r" - - // key INT64_MIN - 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x61, 0x73, // value "s" - - 0x41, 'a', // byte string "a" - 0x02, - - 0x43, 'b', 'a', 'r', // byte string "bar" - 0x03, - - 0x43, 'f', 'o', 'o', // byte string "foo" - 0x04, - - 0x60, // key "" - 0x61, 0x2e, // value "." - - 0x61, 0x65, // key "e" - 0x61, 0x45, // value "E" - - 0x62, 0x61, 0x61, // key "aa" - 0x62, 0x41, 0x41, // value "AA" - // clang-format on - }; - CBORValue::MapValue map; - // Shorter strings sort first in CTAP, thus the “aa” value should be - // serialised last in the map. - map[CBORValue("aa")] = CBORValue("AA"); - map[CBORValue("e")] = CBORValue("E"); - // The empty string is shorter than all others, so should appear first among - // the strings. - map[CBORValue("")] = CBORValue("."); - // Map keys are sorted by major type, by byte length, and then by - // byte-wise lexical order. So all integer type keys should appear before - // key "" and all positive integer keys should appear before negative integer - // keys. - map[CBORValue(-1)] = CBORValue("k"); - map[CBORValue(-24)] = CBORValue("l"); - map[CBORValue(-25)] = CBORValue("m"); - map[CBORValue(-256)] = CBORValue("n"); - map[CBORValue(-257)] = CBORValue("o"); - map[CBORValue(-65537)] = CBORValue("p"); - map[CBORValue(int64_t(-4294967296))] = CBORValue("q"); - map[CBORValue(int64_t(-4294967297))] = CBORValue("r"); - map[CBORValue(std::numeric_limits::min())] = CBORValue("s"); - map[CBORValue(CBORValue::BinaryValue{'a'})] = CBORValue(2); - map[CBORValue(CBORValue::BinaryValue{'b', 'a', 'r'})] = CBORValue(3); - map[CBORValue(CBORValue::BinaryValue{'f', 'o', 'o'})] = CBORValue(4); - map[CBORValue(0)] = CBORValue("a"); - map[CBORValue(23)] = CBORValue("b"); - map[CBORValue(24)] = CBORValue("c"); - map[CBORValue(std::numeric_limits::max())] = CBORValue("d"); - map[CBORValue(256)] = CBORValue("e"); - map[CBORValue(std::numeric_limits::max())] = CBORValue("f"); - map[CBORValue(65536)] = CBORValue("g"); - map[CBORValue(int64_t(std::numeric_limits::max()))] = - CBORValue("h"); - map[CBORValue(int64_t(4294967296))] = CBORValue("i"); - map[CBORValue(std::numeric_limits::max())] = CBORValue("j"); - auto cbor = CBORWriter::Write(CBORValue(map)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), testing::ElementsAreArray( - kMapTestCaseCbor, arraysize(kMapTestCaseCbor))); -} - -TEST(CBORWriterTest, TestWriteMapWithArray) { - static const uint8_t kMapArrayTestCaseCbor[] = { - // clang-format off - 0xa2, // map of 2 pairs - 0x61, 0x61, // "a" - 0x01, - - 0x61, 0x62, // "b" - 0x82, // array with 2 elements - 0x02, - 0x03, - // clang-format on - }; - CBORValue::MapValue map; - map[CBORValue("a")] = CBORValue(1); - CBORValue::ArrayValue array; - array.push_back(CBORValue(2)); - array.push_back(CBORValue(3)); - map[CBORValue("b")] = CBORValue(array); - auto cbor = CBORWriter::Write(CBORValue(map)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), - testing::ElementsAreArray(kMapArrayTestCaseCbor, - arraysize(kMapArrayTestCaseCbor))); -} - -TEST(CBORWriterTest, TestWriteNestedMap) { - static const uint8_t kNestedMapTestCase[] = { - // clang-format off - 0xa2, // map of 2 pairs - 0x61, 0x61, // "a" - 0x01, - - 0x61, 0x62, // "b" - 0xa2, // map of 2 pairs - 0x61, 0x63, // "c" - 0x02, - - 0x61, 0x64, // "d" - 0x03, - // clang-format on - }; - CBORValue::MapValue map; - map[CBORValue("a")] = CBORValue(1); - CBORValue::MapValue nested_map; - nested_map[CBORValue("c")] = CBORValue(2); - nested_map[CBORValue("d")] = CBORValue(3); - map[CBORValue("b")] = CBORValue(nested_map); - auto cbor = CBORWriter::Write(CBORValue(map)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), - testing::ElementsAreArray(kNestedMapTestCase, - arraysize(kNestedMapTestCase))); -} - -TEST(CBORWriterTest, TestSignedExchangeExample) { - // Example adopted from: - // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html - static const uint8_t kSignedExchangeExample[] = { - // clang-format off - 0xa5, // map of 5 pairs - 0x0a, // 10 - 0x01, - - 0x18, 0x64, // 100 - 0x02, - - 0x20, // -1 - 0x03, - - 0x61, 'z', // text string "z" - 0x04, - - 0x62, 'a', 'a', // text string "aa" - 0x05, - - /* - 0x81, 0x18, 0x64, // [100] (array as map key is not yet supported) - 0x06, - - 0x81, 0x20, // [-1] (array as map key is not yet supported) - 0x07, - - 0xf4, // false (boolean as map key is not yet supported) - 0x08, - */ - // clang-format on - }; - CBORValue::MapValue map; - map[CBORValue(10)] = CBORValue(1); - map[CBORValue(100)] = CBORValue(2); - map[CBORValue(-1)] = CBORValue(3); - map[CBORValue("z")] = CBORValue(4); - map[CBORValue("aa")] = CBORValue(5); - - auto cbor = CBORWriter::Write(CBORValue(map)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), - testing::ElementsAreArray(kSignedExchangeExample, - arraysize(kSignedExchangeExample))); -} - -TEST(CBORWriterTest, TestWriteSimpleValue) { - static const struct { - CBORValue::SimpleValue simple_value; - const base::StringPiece cbor; - } kSimpleTestCase[] = { - {CBORValue::SimpleValue::FALSE_VALUE, base::StringPiece("\xf4")}, - {CBORValue::SimpleValue::TRUE_VALUE, base::StringPiece("\xf5")}, - {CBORValue::SimpleValue::NULL_VALUE, base::StringPiece("\xf6")}, - {CBORValue::SimpleValue::UNDEFINED, base::StringPiece("\xf7")}}; - - for (const auto& test_case : kSimpleTestCase) { - auto cbor = CBORWriter::Write(CBORValue(test_case.simple_value)); - ASSERT_TRUE(cbor.has_value()); - EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); - } -} - -// For major type 0, 2, 3, empty CBOR array, and empty CBOR map, the nesting -// depth is expected to be 0 since the CBOR decoder does not need to parse -// any nested CBOR value elements. -TEST(CBORWriterTest, TestWriteSingleLayer) { - const CBORValue simple_uint = CBORValue(1); - const CBORValue simple_string = CBORValue("a"); - const std::vector byte_data = {0x01, 0x02, 0x03, 0x04}; - const CBORValue simple_bytestring = CBORValue(byte_data); - CBORValue::ArrayValue empty_cbor_array; - CBORValue::MapValue empty_cbor_map; - const CBORValue empty_array_value = CBORValue(empty_cbor_array); - const CBORValue empty_map_value = CBORValue(empty_cbor_map); - CBORValue::ArrayValue simple_array; - simple_array.push_back(CBORValue(2)); - CBORValue::MapValue simple_map; - simple_map[CBORValue("b")] = CBORValue(3); - const CBORValue single_layer_cbor_map = CBORValue(simple_map); - const CBORValue single_layer_cbor_array = CBORValue(simple_array); - - EXPECT_TRUE(CBORWriter::Write(simple_uint, 0).has_value()); - EXPECT_TRUE(CBORWriter::Write(simple_string, 0).has_value()); - EXPECT_TRUE(CBORWriter::Write(simple_bytestring, 0).has_value()); - - EXPECT_TRUE(CBORWriter::Write(empty_array_value, 0).has_value()); - EXPECT_TRUE(CBORWriter::Write(empty_map_value, 0).has_value()); - - EXPECT_FALSE(CBORWriter::Write(single_layer_cbor_array, 0).has_value()); - EXPECT_TRUE(CBORWriter::Write(single_layer_cbor_array, 1).has_value()); - - EXPECT_FALSE(CBORWriter::Write(single_layer_cbor_map, 0).has_value()); - EXPECT_TRUE(CBORWriter::Write(single_layer_cbor_map, 1).has_value()); -} - -// Major type 5 nested CBOR map value with following structure. -// {"a": 1, -// "b": {"c": 2, -// "d": 3}} -TEST(CBORWriterTest, NestedMaps) { - CBORValue::MapValue cbor_map; - cbor_map[CBORValue("a")] = CBORValue(1); - CBORValue::MapValue nested_map; - nested_map[CBORValue("c")] = CBORValue(2); - nested_map[CBORValue("d")] = CBORValue(3); - cbor_map[CBORValue("b")] = CBORValue(nested_map); - EXPECT_TRUE(CBORWriter::Write(CBORValue(cbor_map), 2).has_value()); - EXPECT_FALSE(CBORWriter::Write(CBORValue(cbor_map), 1).has_value()); -} - -// Testing Write() function for following CBOR structure with depth of 3. -// [1, -// 2, -// 3, -// {"a": 1, -// "b": {"c": 2, -// "d": 3}}] -TEST(CBORWriterTest, UnbalancedNestedContainers) { - CBORValue::ArrayValue cbor_array; - CBORValue::MapValue cbor_map; - CBORValue::MapValue nested_map; - - cbor_map[CBORValue("a")] = CBORValue(1); - nested_map[CBORValue("c")] = CBORValue(2); - nested_map[CBORValue("d")] = CBORValue(3); - cbor_map[CBORValue("b")] = CBORValue(nested_map); - cbor_array.push_back(CBORValue(1)); - cbor_array.push_back(CBORValue(2)); - cbor_array.push_back(CBORValue(3)); - cbor_array.push_back(CBORValue(cbor_map)); - - EXPECT_TRUE(CBORWriter::Write(CBORValue(cbor_array), 3).has_value()); - EXPECT_FALSE(CBORWriter::Write(CBORValue(cbor_array), 2).has_value()); -} - -// Testing Write() function for following CBOR structure. -// {"a": 1, -// "b": {"c": 2, -// "d": 3 -// "h": { "e": 4, -// "f": 5, -// "g": [6, 7, [8]]}}} -// Since above CBOR contains 5 nesting levels. Thus, Write() is expected to -// return empty optional object when maximum nesting layer size is set to 4. -TEST(CBORWriterTest, OverlyNestedCBOR) { - CBORValue::MapValue map; - CBORValue::MapValue nested_map; - CBORValue::MapValue inner_nested_map; - CBORValue::ArrayValue inner_array; - CBORValue::ArrayValue array; - - map[CBORValue("a")] = CBORValue(1); - nested_map[CBORValue("c")] = CBORValue(2); - nested_map[CBORValue("d")] = CBORValue(3); - inner_nested_map[CBORValue("e")] = CBORValue(4); - inner_nested_map[CBORValue("f")] = CBORValue(5); - inner_array.push_back(CBORValue(6)); - array.push_back(CBORValue(6)); - array.push_back(CBORValue(7)); - array.push_back(CBORValue(inner_array)); - inner_nested_map[CBORValue("g")] = CBORValue(array); - nested_map[CBORValue("h")] = CBORValue(inner_nested_map); - map[CBORValue("b")] = CBORValue(nested_map); - - EXPECT_TRUE(CBORWriter::Write(CBORValue(map), 5).has_value()); - EXPECT_FALSE(CBORWriter::Write(CBORValue(map), 4).has_value()); -} - -} // namespace cbor diff --git a/chromium/components/cbor/constants.h b/chromium/components/cbor/constants.h new file mode 100644 index 00000000000..2df971dc2ed --- /dev/null +++ b/chromium/components/cbor/constants.h @@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CBOR_CONSTANTS_H_ +#define COMPONENTS_CBOR_CONSTANTS_H_ + +#include + +namespace cbor { +namespace constants { + +// Mask selecting the low-order 5 bits of the "initial byte", which is where +// the additional information is encoded. +static constexpr uint8_t kAdditionalInformationMask = 0x1F; +// Mask selecting the high-order 3 bits of the "initial byte", which indicates +// the major type of the encoded value. +static constexpr uint8_t kMajorTypeMask = 0xE0; +// Indicates the number of bits the "initial byte" needs to be shifted to the +// right after applying |kMajorTypeMask| to produce the major type in the +// lowermost bits. +static constexpr uint8_t kMajorTypeBitShift = 5u; +// Indicates the integer is in the following byte. +static constexpr uint8_t kAdditionalInformation1Byte = 24u; +// Indicates the integer is in the next 2 bytes. +static constexpr uint8_t kAdditionalInformation2Bytes = 25u; +// Indicates the integer is in the next 4 bytes. +static constexpr uint8_t kAdditionalInformation4Bytes = 26u; +// Indicates the integer is in the next 8 bytes. +static constexpr uint8_t kAdditionalInformation8Bytes = 27u; + +extern const char kUnsupportedMajorType[]; + +} // namespace constants +} // namespace cbor + +#endif // COMPONENTS_CBOR_CONSTANTS_H_ diff --git a/chromium/components/cbor/reader.cc b/chromium/components/cbor/reader.cc new file mode 100644 index 00000000000..dbab26836d0 --- /dev/null +++ b/chromium/components/cbor/reader.cc @@ -0,0 +1,400 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/cbor/reader.h" + +#include + +#include + +#include "base/numerics/checked_math.h" +#include "base/numerics/safe_conversions.h" +#include "base/stl_util.h" +#include "base/strings/string_util.h" +#include "components/cbor/constants.h" + +namespace cbor { + +namespace constants { +const char kUnsupportedMajorType[] = "Unsupported major type."; +} + +namespace { + +Value::Type GetMajorType(uint8_t initial_data_byte) { + return static_cast( + (initial_data_byte & constants::kMajorTypeMask) >> + constants::kMajorTypeBitShift); +} + +uint8_t GetAdditionalInfo(uint8_t initial_data_byte) { + return initial_data_byte & constants::kAdditionalInformationMask; +} + +// Error messages that correspond to each of the error codes. There is 1 +// exception: we declare |kUnsupportedMajorType| in constants.h in the +// `constants` namespace, because we use it in several files. +const char kNoError[] = "Successfully deserialized to a CBOR value."; +const char kUnknownAdditionalInfo[] = + "Unknown additional info format in the first byte."; +const char kIncompleteCBORData[] = + "Prematurely terminated CBOR data byte array."; +const char kIncorrectMapKeyType[] = + "Specified map key type is not supported by the current implementation."; +const char kTooMuchNesting[] = "Too much nesting."; +const char kInvalidUTF8[] = + "String encodings other than UTF-8 are not allowed."; +const char kExtraneousData[] = "Trailing data bytes are not allowed."; +const char kMapKeyOutOfOrder[] = + "Map keys must be strictly monotonically increasing based on byte length " + "and then by byte-wise lexical order."; +const char kNonMinimalCBOREncoding[] = + "Unsigned integers must be encoded with minimum number of bytes."; +const char kUnsupportedSimpleValue[] = + "Unsupported or unassigned simple value."; +const char kUnsupportedFloatingPointValue[] = + "Floating point numbers are not supported."; +const char kOutOfRangeIntegerValue[] = + "Integer values must be between INT64_MIN and INT64_MAX."; +const char kUnknownError[] = "An unknown error occured."; + +} // namespace + +Reader::Reader(base::span data) + : rest_(data), error_code_(DecoderError::CBOR_NO_ERROR) {} +Reader::~Reader() {} + +// static +base::Optional Reader::Read(base::span data, + DecoderError* error_code_out, + int max_nesting_level) { + size_t num_bytes_consumed; + auto value = + Read(data, &num_bytes_consumed, error_code_out, max_nesting_level); + + if (value && num_bytes_consumed != data.size()) { + if (error_code_out) { + *error_code_out = DecoderError::EXTRANEOUS_DATA; + } + return base::nullopt; + } + + return value; +} + +// static +base::Optional Reader::Read(base::span data, + size_t* num_bytes_consumed, + DecoderError* error_code_out, + int max_nesting_level) { + Reader reader(data); + base::Optional value = + reader.DecodeCompleteDataItem(max_nesting_level); + + auto error = reader.GetErrorCode(); + const bool success = value.has_value(); + DCHECK_EQ(success, error == DecoderError::CBOR_NO_ERROR); + + if (error_code_out) { + *error_code_out = error; + } + + *num_bytes_consumed = + success ? data.size() - reader.num_bytes_remaining() : 0; + return value; +} + +base::Optional Reader::DecodeCompleteDataItem(int max_nesting_level) { + if (max_nesting_level < 0 || max_nesting_level > kCBORMaxDepth) { + error_code_ = DecoderError::TOO_MUCH_NESTING; + return base::nullopt; + } + + base::Optional header = DecodeDataItemHeader(); + if (!header.has_value()) { + return base::nullopt; + } + + switch (header->type) { + case Value::Type::UNSIGNED: + return DecodeValueToUnsigned(header->value); + case Value::Type::NEGATIVE: + return DecodeValueToNegative(header->value); + case Value::Type::BYTE_STRING: + return ReadByteStringContent(*header); + case Value::Type::STRING: + return ReadStringContent(*header); + case Value::Type::ARRAY: + return ReadArrayContent(*header, max_nesting_level); + case Value::Type::MAP: + return ReadMapContent(*header, max_nesting_level); + case Value::Type::SIMPLE_VALUE: + return DecodeToSimpleValue(*header); + case Value::Type::TAG: // We explicitly don't support TAG. + case Value::Type::NONE: + break; + } + + error_code_ = DecoderError::UNSUPPORTED_MAJOR_TYPE; + return base::nullopt; +} + +base::Optional Reader::DecodeDataItemHeader() { + const base::Optional initial_byte = ReadByte(); + if (!initial_byte) { + return base::nullopt; + } + + const auto major_type = GetMajorType(initial_byte.value()); + const uint8_t additional_info = GetAdditionalInfo(initial_byte.value()); + + base::Optional value = ReadVariadicLengthInteger(additional_info); + return value ? base::make_optional( + DataItemHeader{major_type, additional_info, value.value()}) + : base::nullopt; +} + +base::Optional Reader::ReadVariadicLengthInteger( + uint8_t additional_info) { + uint8_t additional_bytes = 0; + if (additional_info < 24) { + return base::make_optional(additional_info); + } else if (additional_info == 24) { + additional_bytes = 1; + } else if (additional_info == 25) { + additional_bytes = 2; + } else if (additional_info == 26) { + additional_bytes = 4; + } else if (additional_info == 27) { + additional_bytes = 8; + } else { + error_code_ = DecoderError::UNKNOWN_ADDITIONAL_INFO; + return base::nullopt; + } + + const base::Optional> bytes = + ReadBytes(additional_bytes); + if (!bytes) { + return base::nullopt; + } + + uint64_t int_data = 0; + for (const uint8_t b : bytes.value()) { + int_data <<= 8; + int_data |= b; + } + + return IsEncodingMinimal(additional_bytes, int_data) + ? base::make_optional(int_data) + : base::nullopt; +} + +base::Optional Reader::DecodeValueToNegative(uint64_t value) { + auto negative_value = -base::CheckedNumeric(value) - 1; + if (!negative_value.IsValid()) { + error_code_ = DecoderError::OUT_OF_RANGE_INTEGER_VALUE; + return base::nullopt; + } + return Value(negative_value.ValueOrDie()); +} + +base::Optional Reader::DecodeValueToUnsigned(uint64_t value) { + auto unsigned_value = base::CheckedNumeric(value); + if (!unsigned_value.IsValid()) { + error_code_ = DecoderError::OUT_OF_RANGE_INTEGER_VALUE; + return base::nullopt; + } + return Value(unsigned_value.ValueOrDie()); +} + +base::Optional Reader::DecodeToSimpleValue( + const DataItemHeader& header) { + // ReadVariadicLengthInteger provides this bound. + CHECK_LE(header.additional_info, 27); + // Floating point numbers are not supported. + if (header.additional_info > 24) { + error_code_ = DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE; + return base::nullopt; + } + + // Since |header.additional_info| <= 24, ReadVariadicLengthInteger also + // provides this bound for |header.value|. + CHECK_LE(header.value, 255u); + // |SimpleValue| is an enum class and so the underlying type is specified to + // be |int|. So this cast is safe. + Value::SimpleValue possibly_unsupported_simple_value = + static_cast(static_cast(header.value)); + switch (possibly_unsupported_simple_value) { + case Value::SimpleValue::FALSE_VALUE: + case Value::SimpleValue::TRUE_VALUE: + case Value::SimpleValue::NULL_VALUE: + case Value::SimpleValue::UNDEFINED: + return Value(possibly_unsupported_simple_value); + } + + error_code_ = DecoderError::UNSUPPORTED_SIMPLE_VALUE; + return base::nullopt; +} + +base::Optional Reader::ReadStringContent( + const Reader::DataItemHeader& header) { + uint64_t num_bytes = header.value; + const base::Optional> bytes = ReadBytes(num_bytes); + if (!bytes) { + return base::nullopt; + } + + std::string cbor_string(bytes->begin(), bytes->end()); + + return HasValidUTF8Format(cbor_string) + ? base::make_optional(Value(std::move(cbor_string))) + : base::nullopt; +} + +base::Optional Reader::ReadByteStringContent( + const Reader::DataItemHeader& header) { + uint64_t num_bytes = header.value; + const base::Optional> bytes = ReadBytes(num_bytes); + if (!bytes) { + return base::nullopt; + } + + std::vector cbor_byte_string(bytes->begin(), bytes->end()); + return Value(std::move(cbor_byte_string)); +} + +base::Optional Reader::ReadArrayContent( + const Reader::DataItemHeader& header, + int max_nesting_level) { + const uint64_t length = header.value; + + Value::ArrayValue cbor_array; + for (uint64_t i = 0; i < length; ++i) { + base::Optional cbor_element = + DecodeCompleteDataItem(max_nesting_level - 1); + if (!cbor_element.has_value()) { + return base::nullopt; + } + cbor_array.push_back(std::move(cbor_element.value())); + } + return Value(std::move(cbor_array)); +} + +base::Optional Reader::ReadMapContent( + const Reader::DataItemHeader& header, + int max_nesting_level) { + const uint64_t length = header.value; + + Value::MapValue cbor_map; + for (uint64_t i = 0; i < length; ++i) { + base::Optional key = DecodeCompleteDataItem(max_nesting_level - 1); + base::Optional value = DecodeCompleteDataItem(max_nesting_level - 1); + if (!key.has_value() || !value.has_value()) { + return base::nullopt; + } + + switch (key.value().type()) { + case Value::Type::UNSIGNED: + case Value::Type::NEGATIVE: + case Value::Type::STRING: + case Value::Type::BYTE_STRING: + break; + default: + error_code_ = DecoderError::INCORRECT_MAP_KEY_TYPE; + return base::nullopt; + } + if (!IsKeyInOrder(key.value(), &cbor_map)) { + return base::nullopt; + } + + cbor_map.insert_or_assign(std::move(key.value()), std::move(value.value())); + } + return Value(std::move(cbor_map)); +} + +base::Optional Reader::ReadByte() { + const base::Optional> bytes = ReadBytes(1); + return bytes ? base::make_optional(bytes.value()[0]) : base::nullopt; +} + +base::Optional> Reader::ReadBytes( + uint64_t num_bytes) { + if (base::strict_cast(rest_.size()) < num_bytes) { + error_code_ = DecoderError::INCOMPLETE_CBOR_DATA; + return base::nullopt; + } + const base::span ret = rest_.first(num_bytes); + rest_ = rest_.subspan(num_bytes); + return ret; +} + +bool Reader::IsEncodingMinimal(uint8_t additional_bytes, uint64_t uint_data) { + if ((additional_bytes == 1 && uint_data < 24) || + uint_data <= (1ULL << 8 * (additional_bytes >> 1)) - 1) { + error_code_ = DecoderError::NON_MINIMAL_CBOR_ENCODING; + return false; + } + return true; +} + +bool Reader::HasValidUTF8Format(const std::string& string_data) { + if (!base::IsStringUTF8(string_data)) { + error_code_ = DecoderError::INVALID_UTF8; + return false; + } + return true; +} + +bool Reader::IsKeyInOrder(const Value& new_key, Value::MapValue* map) { + if (map->empty()) { + return true; + } + + const auto& max_current_key = map->rbegin()->first; + const auto less = map->key_comp(); + if (!less(max_current_key, new_key)) { + error_code_ = DecoderError::OUT_OF_ORDER_KEY; + return false; + } + return true; +} + +// static +const char* Reader::ErrorCodeToString(DecoderError error) { + switch (error) { + case DecoderError::CBOR_NO_ERROR: + return kNoError; + case DecoderError::UNSUPPORTED_MAJOR_TYPE: + return constants::kUnsupportedMajorType; + case DecoderError::UNKNOWN_ADDITIONAL_INFO: + return kUnknownAdditionalInfo; + case DecoderError::INCOMPLETE_CBOR_DATA: + return kIncompleteCBORData; + case DecoderError::INCORRECT_MAP_KEY_TYPE: + return kIncorrectMapKeyType; + case DecoderError::TOO_MUCH_NESTING: + return kTooMuchNesting; + case DecoderError::INVALID_UTF8: + return kInvalidUTF8; + case DecoderError::EXTRANEOUS_DATA: + return kExtraneousData; + case DecoderError::OUT_OF_ORDER_KEY: + return kMapKeyOutOfOrder; + case DecoderError::NON_MINIMAL_CBOR_ENCODING: + return kNonMinimalCBOREncoding; + case DecoderError::UNSUPPORTED_SIMPLE_VALUE: + return kUnsupportedSimpleValue; + case DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE: + return kUnsupportedFloatingPointValue; + case DecoderError::OUT_OF_RANGE_INTEGER_VALUE: + return kOutOfRangeIntegerValue; + case DecoderError::UNKNOWN_ERROR: + return kUnknownError; + default: + NOTREACHED(); + return "Unknown error code."; + } +} + +} // namespace cbor diff --git a/chromium/components/cbor/reader.h b/chromium/components/cbor/reader.h new file mode 100644 index 00000000000..6cf58873b57 --- /dev/null +++ b/chromium/components/cbor/reader.h @@ -0,0 +1,161 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CBOR_READER_H_ +#define COMPONENTS_CBOR_READER_H_ + +#include + +#include +#include + +#include "base/containers/span.h" +#include "base/optional.h" +#include "components/cbor/cbor_export.h" +#include "components/cbor/values.h" + +// Concise Binary Object Representation (CBOR) decoder as defined by +// https://tools.ietf.org/html/rfc7049. This decoder only accepts canonical CBOR +// as defined by section 3.9. +// +// This implementation supports the following major types: +// - 0: Unsigned integers, up to 64-bit values*. +// - 1: Signed integers, up to 64-bit values*. +// - 2: Byte strings. +// - 3: UTF-8 strings. +// - 4: Definite-length arrays. +// - 5: Definite-length maps. +// - 7: Simple values. +// +// * Note: For simplicity, this implementation represents both signed and +// unsigned integers with signed int64_t. This reduces the effective range +// of unsigned integers. +// +// Requirements for canonical CBOR representation: +// - Duplicate keys in maps are not allowed. +// - Keys for maps must be sorted first by length and then by byte-wise +// lexical order. +// +// Known limitations and interpretations of the RFC (and the reasons): +// - Does not support indefinite-length data streams or semantic tags (major +// type 6). (Simplicity; security) +// - Does not support the floating point and BREAK stop code value types in +// major type 7. (Simplicity) +// - Does not support non-character codepoints in major type 3. (Security) +// - Treats incomplete CBOR data items as syntax errors. (Security) +// - Treats trailing data bytes as errors. (Security) +// - Treats unknown additional information formats as syntax errors. +// (Simplicity; security) +// - Limits CBOR value inputs to at most 16 layers of nesting. Callers can +// enforce more shallow nesting by setting |max_nesting_level|. (Efficiency; +// security) +// - Only supports CBOR maps with integer or string type keys, due to the +// cost of serialization when sorting map keys. (Efficiency; simplicity) +// - Does not support simple values that are unassigned/reserved as per RFC +// 7049, and treats them as errors. (Security) + +namespace cbor { + +class CBOR_EXPORT Reader { + public: + enum class DecoderError { + CBOR_NO_ERROR = 0, + UNSUPPORTED_MAJOR_TYPE, + UNKNOWN_ADDITIONAL_INFO, + INCOMPLETE_CBOR_DATA, + INCORRECT_MAP_KEY_TYPE, + TOO_MUCH_NESTING, + INVALID_UTF8, + EXTRANEOUS_DATA, + OUT_OF_ORDER_KEY, + NON_MINIMAL_CBOR_ENCODING, + UNSUPPORTED_SIMPLE_VALUE, + UNSUPPORTED_FLOATING_POINT_VALUE, + OUT_OF_RANGE_INTEGER_VALUE, + UNKNOWN_ERROR, + }; + + // CBOR nested depth sufficient for most use cases. + static const int kCBORMaxDepth = 16; + + ~Reader(); + + // Reads and parses |input_data| into a Value. Returns an empty Optional + // if the input violates any one of the syntax requirements (including unknown + // additional info and incomplete CBOR data). + // + // The caller can optionally provide |error_code_out| to obtain additional + // information about decoding failures. + // + // If the caller provides it, |max_nesting_level| cannot exceed + // |kCBORMaxDepth|. + // + // Returns an empty Optional if not all the data was consumed, and sets + // |error_code_out| to EXTRANEOUS_DATA in this case. + static base::Optional Read(base::span input_data, + DecoderError* error_code_out = nullptr, + int max_nesting_level = kCBORMaxDepth); + + // Never fails with EXTRANEOUS_DATA, but informs the caller of how many bytes + // were consumed through |num_bytes_consumed|. + static base::Optional Read(base::span input_data, + size_t* num_bytes_consumed, + DecoderError* error_code_out = nullptr, + int max_nesting_level = kCBORMaxDepth); + + // Translates errors to human-readable error messages. + static const char* ErrorCodeToString(DecoderError error_code); + + private: + explicit Reader(base::span data); + + // Encapsulates information extracted from the header of a CBOR data item, + // which consists of the initial byte, and a variable-length-encoded integer + // (if any). + struct DataItemHeader { + // The major type decoded from the initial byte. + Value::Type type; + + // The raw 5-bit additional information from the initial byte. + uint8_t additional_info; + + // The integer |value| decoded from the |additional_info| and the + // variable-length-encoded integer, if any. + uint64_t value; + }; + + base::Optional DecodeDataItemHeader(); + base::Optional DecodeCompleteDataItem(int max_nesting_level); + base::Optional DecodeValueToNegative(uint64_t value); + base::Optional DecodeValueToUnsigned(uint64_t value); + base::Optional DecodeToSimpleValue(const DataItemHeader& header); + base::Optional ReadVariadicLengthInteger(uint8_t additional_info); + base::Optional ReadByteStringContent(const DataItemHeader& header); + base::Optional ReadStringContent(const DataItemHeader& header); + base::Optional ReadArrayContent(const DataItemHeader& header, + int max_nesting_level); + base::Optional ReadMapContent(const DataItemHeader& header, + int max_nesting_level); + base::Optional ReadByte(); + base::Optional> ReadBytes(uint64_t num_bytes); + // TODO(crbug/879237): This function's only caller has to make a copy of a + // `span` to satisfy this function's interface. Maybe we can make + // this function take a `const span` and avoid copying? + bool HasValidUTF8Format(const std::string& string_data); + bool IsKeyInOrder(const Value& new_key, Value::MapValue* map); + bool IsEncodingMinimal(uint8_t additional_bytes, uint64_t uint_data); + + DecoderError GetErrorCode() { return error_code_; } + + size_t num_bytes_remaining() const { return rest_.size(); } + + base::span rest_; + DecoderError error_code_; + + DISALLOW_COPY_AND_ASSIGN(Reader); +}; + +} // namespace cbor + +#endif // COMPONENTS_CBOR_READER_H_ diff --git a/chromium/components/cbor/reader_fuzzer.cc b/chromium/components/cbor/reader_fuzzer.cc new file mode 100644 index 00000000000..3a1e0458ad9 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer.cc @@ -0,0 +1,30 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "components/cbor/reader.h" // nogncheck +#include "components/cbor/writer.h" // nogncheck + +namespace cbor { + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector input(data, data + size); + base::Optional cbor = Reader::Read(input); + + if (cbor.has_value()) { + base::Optional> serialized_cbor = + Writer::Write(cbor.value()); + CHECK(serialized_cbor.has_value()); + if (serialized_cbor.has_value()) { + CHECK(serialized_cbor.value().size() == input.size()); + CHECK(memcmp(serialized_cbor.value().data(), input.data(), + input.size()) == 0); + } + } + return 0; +} + +} // namespace cbor diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor0 b/chromium/components/cbor/reader_fuzzer_corpus/cbor0 new file mode 100644 index 00000000000..f76dd238ade Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor0 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor1 b/chromium/components/cbor/reader_fuzzer_corpus/cbor1 new file mode 100644 index 00000000000..6b2aaa76407 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor1 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor10 b/chromium/components/cbor/reader_fuzzer_corpus/cbor10 new file mode 100644 index 00000000000..fed1e13fcfa --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor10 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor11 b/chromium/components/cbor/reader_fuzzer_corpus/cbor11 new file mode 100644 index 00000000000..00a3f0c5362 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor11 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor12 b/chromium/components/cbor/reader_fuzzer_corpus/cbor12 new file mode 100644 index 00000000000..077457ad259 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor12 @@ -0,0 +1 @@ +; \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor13 b/chromium/components/cbor/reader_fuzzer_corpus/cbor13 new file mode 100644 index 00000000000..b4818a3b38b Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor13 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor14 b/chromium/components/cbor/reader_fuzzer_corpus/cbor14 new file mode 100644 index 00000000000..0519ecba6ea --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor14 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor15 b/chromium/components/cbor/reader_fuzzer_corpus/cbor15 new file mode 100644 index 00000000000..e8a0f87653d --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor15 @@ -0,0 +1 @@ +) \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor16 b/chromium/components/cbor/reader_fuzzer_corpus/cbor16 new file mode 100644 index 00000000000..bfefdad18c4 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor16 @@ -0,0 +1 @@ +8c \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor17 b/chromium/components/cbor/reader_fuzzer_corpus/cbor17 new file mode 100644 index 00000000000..5de255544fc --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor17 @@ -0,0 +1 @@ +9 \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor18 b/chromium/components/cbor/reader_fuzzer_corpus/cbor18 new file mode 100644 index 00000000000..e43ae5af822 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor18 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor19 b/chromium/components/cbor/reader_fuzzer_corpus/cbor19 new file mode 100644 index 00000000000..6935671d0de Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor19 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor2 b/chromium/components/cbor/reader_fuzzer_corpus/cbor2 new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor2 @@ -0,0 +1 @@ + diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor20 b/chromium/components/cbor/reader_fuzzer_corpus/cbor20 new file mode 100644 index 00000000000..ed788bb3a4c Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor20 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor21 b/chromium/components/cbor/reader_fuzzer_corpus/cbor21 new file mode 100644 index 00000000000..fc9ea00d188 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor21 @@ -0,0 +1 @@ +?񙙙 \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor22 b/chromium/components/cbor/reader_fuzzer_corpus/cbor22 new file mode 100644 index 00000000000..5ac3929dea8 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor22 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor23 b/chromium/components/cbor/reader_fuzzer_corpus/cbor23 new file mode 100644 index 00000000000..735f4675f10 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor23 @@ -0,0 +1 @@ +{ \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor24 b/chromium/components/cbor/reader_fuzzer_corpus/cbor24 new file mode 100644 index 00000000000..f36a086ed50 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor24 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor25 b/chromium/components/cbor/reader_fuzzer_corpus/cbor25 new file mode 100644 index 00000000000..16f3345724b --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor25 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor26 b/chromium/components/cbor/reader_fuzzer_corpus/cbor26 new file mode 100644 index 00000000000..8e79bf519fe Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor26 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor27 b/chromium/components/cbor/reader_fuzzer_corpus/cbor27 new file mode 100644 index 00000000000..8e144ff3cd2 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor27 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor28 b/chromium/components/cbor/reader_fuzzer_corpus/cbor28 new file mode 100644 index 00000000000..16b0d43402f Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor28 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor29 b/chromium/components/cbor/reader_fuzzer_corpus/cbor29 new file mode 100644 index 00000000000..e5b8b4d8adb Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor29 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor3 b/chromium/components/cbor/reader_fuzzer_corpus/cbor3 new file mode 100644 index 00000000000..c96ab3cc70e --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor3 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor30 b/chromium/components/cbor/reader_fuzzer_corpus/cbor30 new file mode 100644 index 00000000000..815adc3e417 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor30 @@ -0,0 +1 @@ +ffffff \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor31 b/chromium/components/cbor/reader_fuzzer_corpus/cbor31 new file mode 100644 index 00000000000..2b119eb6592 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor31 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor32 b/chromium/components/cbor/reader_fuzzer_corpus/cbor32 new file mode 100644 index 00000000000..d73f58e36a2 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor32 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor33 b/chromium/components/cbor/reader_fuzzer_corpus/cbor33 new file mode 100644 index 00000000000..7c2eb64047e Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor33 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor34 b/chromium/components/cbor/reader_fuzzer_corpus/cbor34 new file mode 100644 index 00000000000..82965f3b13a Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor34 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor35 b/chromium/components/cbor/reader_fuzzer_corpus/cbor35 new file mode 100644 index 00000000000..2a9ccaec94a Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor35 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor36 b/chromium/components/cbor/reader_fuzzer_corpus/cbor36 new file mode 100644 index 00000000000..a9e0eebe00c Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor36 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor37 b/chromium/components/cbor/reader_fuzzer_corpus/cbor37 new file mode 100644 index 00000000000..c90d682d848 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor37 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor38 b/chromium/components/cbor/reader_fuzzer_corpus/cbor38 new file mode 100644 index 00000000000..802efe1966e Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor38 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor39 b/chromium/components/cbor/reader_fuzzer_corpus/cbor39 new file mode 100644 index 00000000000..7a1f61c5343 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor39 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor4 b/chromium/components/cbor/reader_fuzzer_corpus/cbor4 new file mode 100644 index 00000000000..a1910b3f6cc --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor4 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor40 b/chromium/components/cbor/reader_fuzzer_corpus/cbor40 new file mode 100644 index 00000000000..3a6e607aa5a --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor40 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor41 b/chromium/components/cbor/reader_fuzzer_corpus/cbor41 new file mode 100644 index 00000000000..bb7d13c5e9a --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor41 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor42 b/chromium/components/cbor/reader_fuzzer_corpus/cbor42 new file mode 100644 index 00000000000..f7a8cadeb57 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor42 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor43 b/chromium/components/cbor/reader_fuzzer_corpus/cbor43 new file mode 100644 index 00000000000..009080e8e0b --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor43 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor44 b/chromium/components/cbor/reader_fuzzer_corpus/cbor44 new file mode 100644 index 00000000000..04f7b5be698 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor44 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor45 b/chromium/components/cbor/reader_fuzzer_corpus/cbor45 new file mode 100644 index 00000000000..33c4e29de19 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor45 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor46 b/chromium/components/cbor/reader_fuzzer_corpus/cbor46 new file mode 100644 index 00000000000..a61a4624f2c --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor46 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor47 b/chromium/components/cbor/reader_fuzzer_corpus/cbor47 new file mode 100644 index 00000000000..d2fbff8927a --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor47 @@ -0,0 +1 @@ +t2013-03-21T20:04:00Z \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor48 b/chromium/components/cbor/reader_fuzzer_corpus/cbor48 new file mode 100644 index 00000000000..4ecf94681e9 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor48 @@ -0,0 +1 @@ +QKg \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor49 b/chromium/components/cbor/reader_fuzzer_corpus/cbor49 new file mode 100644 index 00000000000..c5c79cf7779 Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor49 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor5 b/chromium/components/cbor/reader_fuzzer_corpus/cbor5 new file mode 100644 index 00000000000..d4e634a6b50 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor5 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor50 b/chromium/components/cbor/reader_fuzzer_corpus/cbor50 new file mode 100644 index 00000000000..7d0120d5bff --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor50 @@ -0,0 +1 @@ +D \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor51 b/chromium/components/cbor/reader_fuzzer_corpus/cbor51 new file mode 100644 index 00000000000..2784fd87e9b --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor51 @@ -0,0 +1 @@ +EdIETF \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor52 b/chromium/components/cbor/reader_fuzzer_corpus/cbor52 new file mode 100644 index 00000000000..b7d2601ab13 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor52 @@ -0,0 +1 @@ + vhttp://www.example.com \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor53 b/chromium/components/cbor/reader_fuzzer_corpus/cbor53 new file mode 100644 index 00000000000..b516b2c489f --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor53 @@ -0,0 +1 @@ +@ \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor54 b/chromium/components/cbor/reader_fuzzer_corpus/cbor54 new file mode 100644 index 00000000000..352e89a8017 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor54 @@ -0,0 +1 @@ +D \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor55 b/chromium/components/cbor/reader_fuzzer_corpus/cbor55 new file mode 100644 index 00000000000..64845fb7679 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor55 @@ -0,0 +1 @@ +` \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor56 b/chromium/components/cbor/reader_fuzzer_corpus/cbor56 new file mode 100644 index 00000000000..7ec9a4b774e --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor56 @@ -0,0 +1 @@ +aa \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor57 b/chromium/components/cbor/reader_fuzzer_corpus/cbor57 new file mode 100644 index 00000000000..743669bb19c --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor57 @@ -0,0 +1 @@ +dIETF \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor58 b/chromium/components/cbor/reader_fuzzer_corpus/cbor58 new file mode 100644 index 00000000000..cce6615381d --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor58 @@ -0,0 +1 @@ +b"\ \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor59 b/chromium/components/cbor/reader_fuzzer_corpus/cbor59 new file mode 100644 index 00000000000..9055a92aa61 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor59 @@ -0,0 +1 @@ +bü \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor6 b/chromium/components/cbor/reader_fuzzer_corpus/cbor6 new file mode 100644 index 00000000000..3b5c90718af --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor6 @@ -0,0 +1 @@ +d \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor60 b/chromium/components/cbor/reader_fuzzer_corpus/cbor60 new file mode 100644 index 00000000000..0868c9a4288 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor60 @@ -0,0 +1 @@ +c水 \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor61 b/chromium/components/cbor/reader_fuzzer_corpus/cbor61 new file mode 100644 index 00000000000..8ea48a07a27 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor61 @@ -0,0 +1 @@ +d𐅑 \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor62 b/chromium/components/cbor/reader_fuzzer_corpus/cbor62 new file mode 100644 index 00000000000..5416677bc7d --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor62 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor63 b/chromium/components/cbor/reader_fuzzer_corpus/cbor63 new file mode 100644 index 00000000000..4cdf6ce18a8 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor63 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor64 b/chromium/components/cbor/reader_fuzzer_corpus/cbor64 new file mode 100644 index 00000000000..80fd3949e51 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor64 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor65 b/chromium/components/cbor/reader_fuzzer_corpus/cbor65 new file mode 100644 index 00000000000..b4495842ec6 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor65 @@ -0,0 +1,2 @@ + +  \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor66 b/chromium/components/cbor/reader_fuzzer_corpus/cbor66 new file mode 100644 index 00000000000..eea1bf0c31f --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor66 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor67 b/chromium/components/cbor/reader_fuzzer_corpus/cbor67 new file mode 100644 index 00000000000..abc169a8cc5 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor67 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor68 b/chromium/components/cbor/reader_fuzzer_corpus/cbor68 new file mode 100644 index 00000000000..81e38473ff6 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor68 @@ -0,0 +1 @@ +aaab \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor69 b/chromium/components/cbor/reader_fuzzer_corpus/cbor69 new file mode 100644 index 00000000000..9b1d08caf44 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor69 @@ -0,0 +1 @@ +aaabac \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor7 b/chromium/components/cbor/reader_fuzzer_corpus/cbor7 new file mode 100644 index 00000000000..fda74fd9c88 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor7 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor70 b/chromium/components/cbor/reader_fuzzer_corpus/cbor70 new file mode 100644 index 00000000000..05bb07fc9d1 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor70 @@ -0,0 +1 @@ +aaaAabaBacaCadaDaeaE \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor71 b/chromium/components/cbor/reader_fuzzer_corpus/cbor71 new file mode 100644 index 00000000000..2681a857cb7 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor71 @@ -0,0 +1 @@ +_BC \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor72 b/chromium/components/cbor/reader_fuzzer_corpus/cbor72 new file mode 100644 index 00000000000..d0daf282398 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor72 @@ -0,0 +1 @@ +estreadming \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor73 b/chromium/components/cbor/reader_fuzzer_corpus/cbor73 new file mode 100644 index 00000000000..422ce24eaac --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor73 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor74 b/chromium/components/cbor/reader_fuzzer_corpus/cbor74 new file mode 100644 index 00000000000..f67cd5703a8 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor74 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor75 b/chromium/components/cbor/reader_fuzzer_corpus/cbor75 new file mode 100644 index 00000000000..78343ed40e3 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor75 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor76 b/chromium/components/cbor/reader_fuzzer_corpus/cbor76 new file mode 100644 index 00000000000..a0f1ea25969 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor76 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor77 b/chromium/components/cbor/reader_fuzzer_corpus/cbor77 new file mode 100644 index 00000000000..dbbf8e51a3f --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor77 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor78 b/chromium/components/cbor/reader_fuzzer_corpus/cbor78 new file mode 100644 index 00000000000..81c9910e824 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor78 @@ -0,0 +1,2 @@ + +  \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor79 b/chromium/components/cbor/reader_fuzzer_corpus/cbor79 new file mode 100644 index 00000000000..018602c1e13 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor79 @@ -0,0 +1 @@ +aaab \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor8 b/chromium/components/cbor/reader_fuzzer_corpus/cbor8 new file mode 100644 index 00000000000..916281951cd Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor8 differ diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor80 b/chromium/components/cbor/reader_fuzzer_corpus/cbor80 new file mode 100644 index 00000000000..151c13e53d3 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor80 @@ -0,0 +1 @@ +aaabac \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor81 b/chromium/components/cbor/reader_fuzzer_corpus/cbor81 new file mode 100644 index 00000000000..c0f4fd5eb32 --- /dev/null +++ b/chromium/components/cbor/reader_fuzzer_corpus/cbor81 @@ -0,0 +1 @@ +cFuncAmt! \ No newline at end of file diff --git a/chromium/components/cbor/reader_fuzzer_corpus/cbor9 b/chromium/components/cbor/reader_fuzzer_corpus/cbor9 new file mode 100644 index 00000000000..4cdcd7ccc3f Binary files /dev/null and b/chromium/components/cbor/reader_fuzzer_corpus/cbor9 differ diff --git a/chromium/components/cbor/reader_unittest.cc b/chromium/components/cbor/reader_unittest.cc new file mode 100644 index 00000000000..6af8d600e8e --- /dev/null +++ b/chromium/components/cbor/reader_unittest.cc @@ -0,0 +1,1236 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "components/cbor/reader.h" + +#include "base/containers/span.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +/* Leveraging RFC 7049 examples from + https://github.com/cbor/test-vectors/blob/master/appendix_a.json. */ +namespace cbor { + +namespace { + +std::vector WithExtraneousData(base::span original) { + std::vector ret(original.cbegin(), original.cend()); + // Add a valid one byte long CBOR data item, namely, an unsigned integer + // with value "1". + ret.push_back(0x01); + return ret; +} + +} // namespace + +TEST(CBORReaderTest, TestReadUint) { + struct UintTestCase { + const int64_t value; + const std::vector cbor_data; + }; + + static const UintTestCase kUintTestCases[] = { + {0, {0x00}}, + {1, {0x01}}, + {23, {0x17}}, + {24, {0x18, 0x18}}, + {std::numeric_limits::max(), {0x18, 0xff}}, + {1LL << 8, {0x19, 0x01, 0x00}}, + {std::numeric_limits::max(), {0x19, 0xff, 0xff}}, + {1LL << 16, {0x1a, 0x00, 0x01, 0x00, 0x00}}, + {std::numeric_limits::max(), {0x1a, 0xff, 0xff, 0xff, 0xff}}, + {1LL << 32, {0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, + {std::numeric_limits::max(), + {0x1b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}, + }; + + for (const UintTestCase& test_case : kUintTestCases) { + SCOPED_TRACE(testing::Message() << "testing uint: " << test_case.value); + + base::Optional cbor = Reader::Read(test_case.cbor_data); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::UNSIGNED); + EXPECT_EQ(cbor.value().GetInteger(), test_case.value); + + auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, + &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::UNSIGNED); + EXPECT_EQ(cbor.value().GetInteger(), test_case.value); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); + } +} + +TEST(CBORReaderTest, TestUintEncodedWithNonMinimumByteLength) { + static const std::vector non_minimal_uint_encodings[] = { + // Uint 23 encoded with 1 byte. + {0x18, 0x17}, + // Uint 255 encoded with 2 bytes. + {0x19, 0x00, 0xff}, + // Uint 65535 encoded with 4 byte. + {0x1a, 0x00, 0x00, 0xff, 0xff}, + // Uint 4294967295 encoded with 8 byte. + {0x1b, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}, + + // When decoding byte has more than one syntax error, the first syntax + // error encountered during deserialization is returned as the error code. + { + 0xa2, // map with non-minimally encoded key + 0x17, // key 24 + 0x61, 0x42, // value :"B" + + 0x18, 0x17, // key 23 encoded with extra byte + 0x61, 0x45 // value "E" + }, + { + 0xa2, // map with out of order and non-minimally encoded key + 0x18, 0x17, // key 23 encoded with extra byte + 0x61, 0x45, // value "E" + 0x17, // key 23 + 0x61, 0x42 // value :"B" + }, + { + 0xa2, // map with duplicate non-minimally encoded key + 0x18, 0x17, // key 23 encoded with extra byte + 0x61, 0x45, // value "E" + 0x18, 0x17, // key 23 encoded with extra byte + 0x61, 0x42 // value :"B" + }, + }; + + int test_case_index = 0; + Reader::DecoderError error_code; + for (const auto& non_minimal_uint : non_minimal_uint_encodings) { + SCOPED_TRACE(testing::Message() + << "testing element at index : " << test_case_index++); + + base::Optional cbor = Reader::Read(non_minimal_uint, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::NON_MINIMAL_CBOR_ENCODING); + } +} + +TEST(CBORReaderTest, TestReadNegativeInt) { + struct NegativeIntTestCase { + const int64_t negative_int; + const std::vector cbor_data; + }; + + static const NegativeIntTestCase kNegativeIntTestCases[] = { + {-1LL, {0x20}}, + {-24LL, {0x37}}, + {-25LL, {0x38, 0x18}}, + {-256LL, {0x38, 0xff}}, + {-1000LL, {0x39, 0x03, 0xe7}}, + {-1000000LL, {0x3a, 0x00, 0x0f, 0x42, 0x3f}}, + {-4294967296LL, {0x3a, 0xff, 0xff, 0xff, 0xff}}, + {std::numeric_limits::min(), + {0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}}; + + for (const NegativeIntTestCase& test_case : kNegativeIntTestCases) { + SCOPED_TRACE(testing::Message() + << "testing negative int : " << test_case.negative_int); + + base::Optional cbor = Reader::Read(test_case.cbor_data); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::NEGATIVE); + EXPECT_EQ(cbor.value().GetInteger(), test_case.negative_int); + + auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, + &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::NEGATIVE); + EXPECT_EQ(cbor.value().GetInteger(), test_case.negative_int); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); + } +} + +TEST(CBORReaderTest, TestReadBytes) { + struct ByteTestCase { + const std::vector value; + const std::vector cbor_data; + }; + + static const ByteTestCase kByteStringTestCases[] = { + // clang-format off + {{}, {0x40}}, + {{0x01, 0x02, 0x03, 0x04}, {0x44, 0x01, 0x02, 0x03, 0x04}}, + // clang-format on + }; + + int element_index = 0; + for (const ByteTestCase& test_case : kByteStringTestCases) { + SCOPED_TRACE(testing::Message() + << "testing string test case at : " << element_index++); + + base::Optional cbor = Reader::Read(test_case.cbor_data); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::BYTE_STRING); + EXPECT_EQ(cbor.value().GetBytestring(), test_case.value); + + auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, + &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::BYTE_STRING); + EXPECT_EQ(cbor.value().GetBytestring(), test_case.value); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); + } +} + +TEST(CBORReaderTest, TestReadString) { + struct StringTestCase { + const std::string value; + const std::vector cbor_data; + }; + + static const StringTestCase kStringTestCases[] = { + {"", {0x60}}, + {"a", {0x61, 0x61}}, + {"IETF", {0x64, 0x49, 0x45, 0x54, 0x46}}, + {"\"\\", {0x62, 0x22, 0x5c}}, + {"\xc3\xbc", {0x62, 0xc3, 0xbc}}, + {"\xe6\xb0\xb4", {0x63, 0xe6, 0xb0, 0xb4}}, + {"\xf0\x90\x85\x91", {0x64, 0xf0, 0x90, 0x85, 0x91}}, + }; + + for (const StringTestCase& test_case : kStringTestCases) { + SCOPED_TRACE(testing::Message() + << "testing string value : " << test_case.value); + + base::Optional cbor = Reader::Read(test_case.cbor_data); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::STRING); + EXPECT_EQ(cbor.value().GetString(), test_case.value); + + auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, + &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::STRING); + EXPECT_EQ(cbor.value().GetString(), test_case.value); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); + } +} + +TEST(CBORReaderTest, TestReadStringWithNUL) { + static const struct { + const std::string value; + const std::vector cbor_data; + } kStringTestCases[] = { + {std::string("string_without_nul"), + {0x72, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x5F, 0x77, 0x69, 0x74, 0x68, + 0x6F, 0x75, 0x74, 0x5F, 0x6E, 0x75, 0x6C}}, + {std::string("nul_terminated_string\0", 22), + {0x76, 0x6E, 0x75, 0x6C, 0x5F, 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x61, + 0x74, 0x65, 0x64, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00}}, + {std::string("embedded\0nul", 12), + {0x6C, 0x65, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x00, 0x6E, 0x75, + 0x6C}}, + {std::string("trailing_nuls\0\0", 15), + {0x6F, 0x74, 0x72, 0x61, 0x69, 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x6E, 0x75, + 0x6C, 0x73, 0x00, 0x00}}, + }; + + for (const auto& test_case : kStringTestCases) { + SCOPED_TRACE(testing::Message() + << "testing string with nul bytes :" << test_case.value); + + base::Optional cbor = Reader::Read(test_case.cbor_data); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::STRING); + EXPECT_EQ(cbor.value().GetString(), test_case.value); + + auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, + &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::STRING); + EXPECT_EQ(cbor.value().GetString(), test_case.value); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); + } +} + +TEST(CBORReaderTest, TestReadStringWithInvalidByteSequenceAfterNUL) { + // UTF-8 validation should not stop at the first NUL character in the string. + // That is, a string with an invalid byte sequence should fail UTF-8 + // validation even if the invalid character is located after one or more NUL + // characters. Here, 0xA6 is an unexpected continuation byte. + static const std::vector string_with_invalid_continuation_byte = { + 0x63, 0x00, 0x00, 0xA6}; + Reader::DecoderError error_code; + base::Optional cbor = + Reader::Read(string_with_invalid_continuation_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::INVALID_UTF8); +} + +TEST(CBORReaderTest, TestReadArray) { + static const std::vector kArrayTestCaseCbor = { + // clang-format off + 0x98, 0x19, // array of 25 elements + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x18, 0x18, 0x19, + // clang-format on + }; + + base::Optional cbor = Reader::Read(kArrayTestCaseCbor); + ASSERT_TRUE(cbor.has_value()); + const Value cbor_array = std::move(cbor.value()); + ASSERT_EQ(cbor_array.type(), Value::Type::ARRAY); + ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25)); + + std::vector array; + for (int i = 0; i < 25; i++) { + SCOPED_TRACE(testing::Message() << "testing array element at index " << i); + + ASSERT_EQ(cbor_array.GetArray()[i].type(), Value::Type::UNSIGNED); + EXPECT_EQ(cbor_array.GetArray()[i].GetInteger(), + static_cast(i + 1)); + } + + auto cbor_data_with_extra_byte = WithExtraneousData(kArrayTestCaseCbor); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = + Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor_array.type(), Value::Type::ARRAY); + ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25)); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, kArrayTestCaseCbor.size()); +} + +TEST(CBORReaderTest, TestReadMapWithMapValue) { + static const std::vector kMapTestCaseCbor = { + // clang-format off + 0xa4, // map with 4 key value pairs: + 0x18, 0x18, // 24 + 0x63, 0x61, 0x62, 0x63, // "abc" + + 0x60, // "" + 0x61, 0x2e, // "." + + 0x61, 0x62, // "b" + 0x61, 0x42, // "B" + + 0x62, 0x61, 0x61, // "aa" + 0x62, 0x41, 0x41, // "AA" + // clang-format on + }; + + base::Optional cbor = Reader::Read(kMapTestCaseCbor); + ASSERT_TRUE(cbor.has_value()); + const Value cbor_val = std::move(cbor.value()); + ASSERT_EQ(cbor_val.type(), Value::Type::MAP); + ASSERT_EQ(cbor_val.GetMap().size(), 4u); + + const Value key_uint(24); + ASSERT_EQ(cbor_val.GetMap().count(key_uint), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_uint)->second.type(), + Value::Type::STRING); + EXPECT_EQ(cbor_val.GetMap().find(key_uint)->second.GetString(), "abc"); + + const Value key_empty_string(""); + ASSERT_EQ(cbor_val.GetMap().count(key_empty_string), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_empty_string)->second.type(), + Value::Type::STRING); + EXPECT_EQ(cbor_val.GetMap().find(key_empty_string)->second.GetString(), "."); + + const Value key_b("b"); + ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(), Value::Type::STRING); + EXPECT_EQ(cbor_val.GetMap().find(key_b)->second.GetString(), "B"); + + const Value key_aa("aa"); + ASSERT_EQ(cbor_val.GetMap().count(key_aa), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_aa)->second.type(), Value::Type::STRING); + EXPECT_EQ(cbor_val.GetMap().find(key_aa)->second.GetString(), "AA"); + + auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCaseCbor); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = + Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor_val.type(), Value::Type::MAP); + ASSERT_EQ(cbor_val.GetMap().size(), 4u); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, kMapTestCaseCbor.size()); +} + +TEST(CBORReaderTest, TestReadMapWithIntegerKeys) { + static const std::vector kMapWithIntegerKeyCbor = { + // clang-format off + 0xA4, // map with 4 key value pairs + 0x01, // key : 1 + 0x61, 0x61, // value : "a" + + 0x09, // key : 9 + 0x61, 0x62, // value : "b" + + 0x19, 0x03, 0xE7, // key : 999 + 0x61, 0x63, // value "c" + + 0x19, 0x04, 0x57, // key : 1111 + 0x61, 0x64, // value : "d" + // clang-format on + }; + + base::Optional cbor = Reader::Read(kMapWithIntegerKeyCbor); + ASSERT_TRUE(cbor.has_value()); + const Value cbor_val = std::move(cbor.value()); + ASSERT_EQ(cbor_val.type(), Value::Type::MAP); + ASSERT_EQ(cbor_val.GetMap().size(), 4u); + + const Value key_1(1); + ASSERT_EQ(cbor_val.GetMap().count(key_1), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(), Value::Type::STRING); + EXPECT_EQ(cbor_val.GetMap().find(key_1)->second.GetString(), "a"); + + const Value key_9(9); + ASSERT_EQ(cbor_val.GetMap().count(key_9), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_9)->second.type(), Value::Type::STRING); + EXPECT_EQ(cbor_val.GetMap().find(key_9)->second.GetString(), "b"); + + const Value key_999(999); + ASSERT_EQ(cbor_val.GetMap().count(key_999), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_999)->second.type(), + Value::Type::STRING); + EXPECT_EQ(cbor_val.GetMap().find(key_999)->second.GetString(), "c"); + + const Value key_1111(1111); + ASSERT_EQ(cbor_val.GetMap().count(key_1111), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_1111)->second.type(), + Value::Type::STRING); + EXPECT_EQ(cbor_val.GetMap().find(key_1111)->second.GetString(), "d"); + + auto cbor_data_with_extra_byte = WithExtraneousData(kMapWithIntegerKeyCbor); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = + Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor_val.type(), Value::Type::MAP); + ASSERT_EQ(cbor_val.GetMap().size(), 4u); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, kMapWithIntegerKeyCbor.size()); +} + +TEST(CBORReaderTest, TestReadMapWithNegativeIntegersKeys) { + static const std::vector kMapWithIntegerKeyCbor = { + // clang-format off + 0xA3, // map with 3 key value pairs + 0x20, // key : -1 + 0x01, + + 0x21, // key : -2 + 0x02, + + 0x38, 0x63, // key : -100 + 0x03, + // clang-format on + }; + + base::Optional cbor = Reader::Read(kMapWithIntegerKeyCbor); + ASSERT_TRUE(cbor.has_value()); + const Value cbor_val = std::move(cbor.value()); + ASSERT_EQ(cbor_val.type(), Value::Type::MAP); + ASSERT_EQ(cbor_val.GetMap().size(), 3u); + + const Value key_1(-1); + ASSERT_EQ(cbor_val.GetMap().count(key_1), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(), + Value::Type::UNSIGNED); + EXPECT_EQ(cbor_val.GetMap().find(key_1)->second.GetInteger(), 1); + + const Value key_2(-2); + ASSERT_EQ(cbor_val.GetMap().count(key_2), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_2)->second.type(), + Value::Type::UNSIGNED); + EXPECT_EQ(cbor_val.GetMap().find(key_2)->second.GetInteger(), 2); + + const Value key_100(-100); + ASSERT_EQ(cbor_val.GetMap().count(key_100), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_100)->second.type(), + Value::Type::UNSIGNED); + EXPECT_EQ(cbor_val.GetMap().find(key_100)->second.GetInteger(), 3); + + auto cbor_data_with_extra_byte = WithExtraneousData(kMapWithIntegerKeyCbor); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = + Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor_val.type(), Value::Type::MAP); + ASSERT_EQ(cbor_val.GetMap().size(), 3u); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, kMapWithIntegerKeyCbor.size()); +} + +TEST(CBORReaderTest, TestReadMapWithArray) { + static const std::vector kMapArrayTestCaseCbor = { + // clang-format off + 0xa2, // map of 2 pairs + 0x61, 0x61, // "a" + 0x01, + + 0x61, 0x62, // "b" + 0x82, // array with 2 elements + 0x02, + 0x03, + // clang-format on + }; + + base::Optional cbor = Reader::Read(kMapArrayTestCaseCbor); + ASSERT_TRUE(cbor.has_value()); + const Value cbor_val = std::move(cbor.value()); + ASSERT_EQ(cbor_val.type(), Value::Type::MAP); + ASSERT_EQ(cbor_val.GetMap().size(), 2u); + + const Value key_a("a"); + ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(), + Value::Type::UNSIGNED); + EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u); + + const Value key_b("b"); + ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(), Value::Type::ARRAY); + + const Value nested_array = cbor_val.GetMap().find(key_b)->second.Clone(); + ASSERT_EQ(nested_array.GetArray().size(), 2u); + for (int i = 0; i < 2; i++) { + ASSERT_THAT(nested_array.GetArray()[i].type(), Value::Type::UNSIGNED); + EXPECT_EQ(nested_array.GetArray()[i].GetInteger(), + static_cast(i + 2)); + } + + auto cbor_data_with_extra_byte = WithExtraneousData(kMapArrayTestCaseCbor); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = + Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor_val.type(), Value::Type::MAP); + ASSERT_EQ(cbor_val.GetMap().size(), 2u); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, kMapArrayTestCaseCbor.size()); +} + +TEST(CBORReaderTest, TestReadMapWithTextStringKeys) { + static const std::vector kMapTestCase{ + // clang-format off + 0xa2, // map of 2 pairs + 0x61, 'k', // text string "k" + 0x61, 'v', + + 0x63, 'f', 'o', 'o', // text string "foo" + 0x63, 'b', 'a', 'r', + // clang-format on + }; + + Reader::DecoderError error_code; + base::Optional cbor = Reader::Read(kMapTestCase, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor->type(), Value::Type::MAP); + ASSERT_EQ(cbor->GetMap().size(), 2u); + + const Value key_k("k"); + ASSERT_EQ(cbor->GetMap().count(key_k), 1u); + ASSERT_EQ(cbor->GetMap().find(key_k)->second.type(), Value::Type::STRING); + EXPECT_EQ(cbor->GetMap().find(key_k)->second.GetString(), "v"); + + const Value key_foo("foo"); + ASSERT_EQ(cbor->GetMap().count(key_foo), 1u); + ASSERT_EQ(cbor->GetMap().find(key_foo)->second.type(), Value::Type::STRING); + EXPECT_EQ(cbor->GetMap().find(key_foo)->second.GetString(), "bar"); + + auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase); + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = + Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor->type(), Value::Type::MAP); + ASSERT_EQ(cbor->GetMap().size(), 2u); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, kMapTestCase.size()); +} + +TEST(CBORReaderTest, TestReadMapWithByteStringKeys) { + static const std::vector kMapTestCase{ + // clang-format off + 0xa2, // map of 2 pairs + 0x41, 'k', // byte string "k" + 0x41, 'v', + + 0x43, 'f', 'o', 'o', // byte string "foo" + 0x43, 'b', 'a', 'r', + // clang-format on + }; + + Reader::DecoderError error_code; + base::Optional cbor = Reader::Read(kMapTestCase, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor->type(), Value::Type::MAP); + ASSERT_EQ(cbor->GetMap().size(), 2u); + + const Value key_k(std::vector{'k'}); + ASSERT_EQ(cbor->GetMap().count(key_k), 1u); + ASSERT_EQ(cbor->GetMap().find(key_k)->second.type(), + Value::Type::BYTE_STRING); + EXPECT_EQ(cbor->GetMap().find(key_k)->second.GetBytestring(), + std::vector{'v'}); + + const Value key_foo(std::vector{'f', 'o', 'o'}); + ASSERT_EQ(cbor->GetMap().count(key_foo), 1u); + ASSERT_EQ(cbor->GetMap().find(key_foo)->second.type(), + Value::Type::BYTE_STRING); + static const std::vector kBarBytes{'b', 'a', 'r'}; + EXPECT_EQ(cbor->GetMap().find(key_foo)->second.GetBytestring(), kBarBytes); + + auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase); + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = + Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor->type(), Value::Type::MAP); + ASSERT_EQ(cbor->GetMap().size(), 2u); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, kMapTestCase.size()); +} + +TEST(CBORReaderTest, TestReadMapWithMixedKeys) { + // Example adopted from: + // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html + static const uint8_t kMapTestCase[] = { + // clang-format off + 0xa6, // map of 6 pairs + 0x0a, // 10 + 0x00, + + 0x18, 0x64, // 100 + 0x01, + + 0x20, // -1 + 0x02, + + // This entry is not in the example, but added to test byte string key + 0x42, 'x', 'y', // byte string "xy" + 0x03, + + 0x61, 'z', // text string "z" + 0x04, + + 0x62, 'a', 'a', // text string "aa" + 0x05, + + /* + 0x81, 0x18, 0x64, // [100] (array as map key is not yet supported) + 0x06, + + 0x81, 0x20, // [-1] (array as map key is not yet supported) + 0x07, + + 0xf4, // false (boolean as map key is not yet supported) + 0x08, + */ + // clang-format on + }; + + Reader::DecoderError error_code; + base::Optional cbor = Reader::Read(kMapTestCase, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor->type(), Value::Type::MAP); + ASSERT_EQ(cbor->GetMap().size(), 6u); + + std::vector keys; + keys.emplace_back(10); + keys.emplace_back(100); + keys.emplace_back(-1); + keys.emplace_back(Value::BinaryValue{'x', 'y'}); + keys.emplace_back("z"); + keys.emplace_back("aa"); + for (size_t i = 0; i < keys.size(); ++i) { + SCOPED_TRACE(testing::Message() << "testing key at index: " << i); + ASSERT_EQ(cbor->GetMap().count(keys[i]), 1u); + ASSERT_EQ(cbor->GetMap().find(keys[i])->second.type(), + Value::Type::UNSIGNED); + EXPECT_EQ(cbor->GetMap().find(keys[i])->second.GetInteger(), + static_cast(i)); + } + + auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase); + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = + Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor->type(), Value::Type::MAP); + ASSERT_EQ(cbor->GetMap().size(), 6u); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, arraysize(kMapTestCase)); +} + +TEST(CBORReaderTest, TestReadNestedMap) { + static const std::vector kNestedMapTestCase = { + // clang-format off + 0xa2, // map of 2 pairs + 0x61, 0x61, // "a" + 0x01, + + 0x61, 0x62, // "b" + 0xa2, // map of 2 pairs + 0x61, 0x63, // "c" + 0x02, + + 0x61, 0x64, // "d" + 0x03, + // clang-format on + }; + + base::Optional cbor = Reader::Read(kNestedMapTestCase); + ASSERT_TRUE(cbor.has_value()); + const Value cbor_val = std::move(cbor.value()); + ASSERT_EQ(cbor_val.type(), Value::Type::MAP); + ASSERT_EQ(cbor_val.GetMap().size(), 2u); + + const Value key_a("a"); + ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u); + ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(), + Value::Type::UNSIGNED); + EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u); + + const Value key_b("b"); + ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u); + const Value nested_map = cbor_val.GetMap().find(key_b)->second.Clone(); + ASSERT_EQ(nested_map.type(), Value::Type::MAP); + ASSERT_EQ(nested_map.GetMap().size(), 2u); + + const Value key_c("c"); + ASSERT_EQ(nested_map.GetMap().count(key_c), 1u); + ASSERT_EQ(nested_map.GetMap().find(key_c)->second.type(), + Value::Type::UNSIGNED); + EXPECT_EQ(nested_map.GetMap().find(key_c)->second.GetInteger(), 2u); + + const Value key_d("d"); + ASSERT_EQ(nested_map.GetMap().count(key_d), 1u); + ASSERT_EQ(nested_map.GetMap().find(key_d)->second.type(), + Value::Type::UNSIGNED); + EXPECT_EQ(nested_map.GetMap().find(key_d)->second.GetInteger(), 3u); +} + +TEST(CBORReaderTest, TestIntegerRange) { + static const std::vector kMaxPositiveInt = { + 0x1b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + static const std::vector kMinNegativeInt = { + 0x3b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + base::Optional max_positive_int = Reader::Read(kMaxPositiveInt); + ASSERT_TRUE(max_positive_int.has_value()); + EXPECT_EQ(max_positive_int.value().GetInteger(), INT64_MAX); + + base::Optional min_negative_int = Reader::Read(kMinNegativeInt); + ASSERT_TRUE(min_negative_int.has_value()); + EXPECT_EQ(min_negative_int.value().GetInteger(), INT64_MIN); +} + +TEST(CBORReaderTest, TestIntegerOutOfRangeError) { + static const std::vector kOutOfRangePositiveInt = { + 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + static const std::vector kOutOfRangeNegativeInt = { + 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + Reader::DecoderError error_code; + base::Optional positive_int_out_of_range_cbor = + Reader::Read(kOutOfRangePositiveInt, &error_code); + EXPECT_FALSE(positive_int_out_of_range_cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE); + + base::Optional negative_int_out_of_range_cbor = + Reader::Read(kOutOfRangeNegativeInt, &error_code); + EXPECT_FALSE(negative_int_out_of_range_cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE); +} + +TEST(CBORReaderTest, TestReadSimpleValue) { + static const struct { + const Value::SimpleValue value; + const std::vector cbor_data; + } kSimpleValueTestCases[] = { + {Value::SimpleValue::FALSE_VALUE, {0xf4}}, + {Value::SimpleValue::TRUE_VALUE, {0xf5}}, + {Value::SimpleValue::NULL_VALUE, {0xf6}}, + {Value::SimpleValue::UNDEFINED, {0xf7}}, + }; + + int test_element_index = 0; + for (const auto& test_case : kSimpleValueTestCases) { + SCOPED_TRACE(testing::Message() + << "testing simple value at index : " << test_element_index++); + + base::Optional cbor = Reader::Read(test_case.cbor_data); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::SIMPLE_VALUE); + EXPECT_EQ(cbor.value().GetSimpleValue(), test_case.value); + + auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data); + Reader::DecoderError error_code; + cbor = Reader::Read(cbor_data_with_extra_byte, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + + size_t num_bytes_consumed; + cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, + &error_code); + ASSERT_TRUE(cbor.has_value()); + ASSERT_EQ(cbor.value().type(), Value::Type::SIMPLE_VALUE); + EXPECT_EQ(cbor.value().GetSimpleValue(), test_case.value); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size()); + } +} + +TEST(CBORReaderTest, TestReadUnsupportedFloatingPointNumbers) { + static const std::vector floating_point_cbors[] = { + // 16 bit floating point value. + {0xf9, 0x10, 0x00}, + // 32 bit floating point value. + {0xfa, 0x10, 0x00, 0x00, 0x00}, + // 64 bit floating point value. + {0xfb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + + for (const auto& unsupported_floating_point : floating_point_cbors) { + SCOPED_TRACE(testing::Message() + << "testing unsupported floating point : " + << testing::PrintToString(unsupported_floating_point)); + Reader::DecoderError error_code; + base::Optional cbor = + Reader::Read(unsupported_floating_point, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, + Reader::DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE); + } +} + +TEST(CBORReaderTest, TestIncompleteCBORDataError) { + static const std::vector incomplete_cbor_list[] = { + // Additional info byte corresponds to unsigned int that corresponds + // to 2 additional bytes. But actual data encoded in one byte. + {0x19, 0x03}, + // CBOR bytestring of length 3 encoded with additional info of length 4. + {0x44, 0x01, 0x02, 0x03}, + // CBOR string data "IETF" of length 4 encoded with additional info of + // length 5. + {0x65, 0x49, 0x45, 0x54, 0x46}, + // CBOR array of length 1 encoded with additional info of length 2. + {0x82, 0x02}, + // CBOR map with single key value pair encoded with additional info of + // length 2. + {0xa2, 0x61, 0x61, 0x01}, + {0x18}, // unsigned with pending 1 byte of numeric value. + {0x99}, // array with pending 2 byte of numeric value (length). + {0xba}, // map with pending 4 byte of numeric value (length). + {0x5b}, // byte string with pending 4 byte of numeric value (length). + {0x3b}, // negative integer with pending 8 byte of numeric value. + {0x99, 0x01}, // array with pending 2 byte of numeric value (length), + // with only 1 byte of additional data. + {0xba, 0x01, 0x02, 0x03}, // map with pending 4 byte of numeric value + // (length), with only 3 bytes of additional + // data. + {0x3b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07}, // negative integer with pending 8 byte of + // numeric value, with only 7 bytes of + // additional data. + }; + + int test_element_index = 0; + for (const auto& incomplete_data : incomplete_cbor_list) { + SCOPED_TRACE(testing::Message() << "testing incomplete data at index : " + << test_element_index++); + + Reader::DecoderError error_code; + base::Optional cbor = Reader::Read(incomplete_data, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::INCOMPLETE_CBOR_DATA); + } +} + +// While RFC 7049 allows CBOR map keys with all types, current decoder only +// supports unsigned integer and string keys. +TEST(CBORReaderTest, TestUnsupportedMapKeyFormatError) { + static const std::vector kMapWithUintKey = { + // clang-format off + 0xa2, // map of 2 pairs + + 0x82, 0x01, 0x02, // invalid key : [1, 2] + 0x02, // value : 2 + + 0x61, 0x64, // key : "d" + 0x03, // value : 3 + // clang-format on + }; + + Reader::DecoderError error_code; + base::Optional cbor = Reader::Read(kMapWithUintKey, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::INCORRECT_MAP_KEY_TYPE); +} + +TEST(CBORReaderTest, TestUnknownAdditionalInfoError) { + static const std::vector kUnknownAdditionalInfoList[] = { + // "IETF" encoded with major type 3 and additional info of 28. + {0x7C, 0x49, 0x45, 0x54, 0x46}, + // "\"\\" encoded with major type 3 and additional info of 29. + {0x7D, 0x22, 0x5c}, + // "\xc3\xbc" encoded with major type 3 and additional info of 30. + {0x7E, 0xc3, 0xbc}, + // "\xe6\xb0\xb4" encoded with major type 3 and additional info of 31. + {0x7F, 0xe6, 0xb0, 0xb4}, + // Major type 7, additional information 28: unassigned. + {0xFC}, + // Major type 7, additional information 29: unassigned. + {0xFD}, + // Major type 7, additional information 30: unassigned. + {0xFE}, + // Major type 7, additional information 31: "break" stop code for + // indefinite-length items. + {0xFF}, + }; + + int test_element_index = 0; + for (const auto& incorrect_cbor : kUnknownAdditionalInfoList) { + SCOPED_TRACE(testing::Message() + << "testing data at index : " << test_element_index++); + + Reader::DecoderError error_code; + base::Optional cbor = Reader::Read(incorrect_cbor, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::UNKNOWN_ADDITIONAL_INFO); + } +} + +TEST(CBORReaderTest, TestTooMuchNestingError) { + static const std::vector kZeroDepthCBORList[] = { + // Unsigned int with value 100. + {0x18, 0x64}, + // CBOR bytestring of length 4. + {0x44, 0x01, 0x02, 0x03, 0x04}, + // CBOR string of corresponding to "IETF. + {0x64, 0x49, 0x45, 0x54, 0x46}, + // Empty CBOR array. + {0x80}, + // Empty CBOR Map + {0xa0}, + }; + + int test_element_index = 0; + for (const auto& zero_depth_data : kZeroDepthCBORList) { + SCOPED_TRACE(testing::Message() + << "testing zero nested data : " << test_element_index++); + Reader::DecoderError error_code; + base::Optional cbor = Reader::Read(zero_depth_data, &error_code, 0); + EXPECT_TRUE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + } + + // Corresponds to a CBOR structure with a nesting depth of 2: + // {"a": 1, + // "b": [2, 3]} + static const std::vector kNestedCBORData = { + // clang-format off + 0xa2, // map of 2 pairs + 0x61, 0x61, // "a" + 0x01, + + 0x61, 0x62, // "b" + 0x82, // array with 2 elements + 0x02, + 0x03, + // clang-format on + }; + + Reader::DecoderError error_code; + base::Optional cbor_single_layer_max = + Reader::Read(kNestedCBORData, &error_code, 1); + EXPECT_FALSE(cbor_single_layer_max.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::TOO_MUCH_NESTING); + + base::Optional cbor_double_layer_max = + Reader::Read(kNestedCBORData, &error_code, 2); + EXPECT_TRUE(cbor_double_layer_max.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); +} + +TEST(CBORReaderTest, TestOutOfOrderKeyError) { + static const std::vector kMapsWithUnsortedKeys[] = { + // clang-format off + {0xa2, // map with 2 keys with same major type and length + 0x61, 0x62, // key "b" + 0x61, 0x42, // value "B" + + 0x61, 0x61, // key "a" (out of order byte-wise lexically) + 0x61, 0x45 // value "E" + }, + {0xa2, // map with 2 keys with different major type + 0x61, 0x62, // key "b" + 0x02, // value 2 + + // key 1000 (out of order since lower major type sorts first) + 0x19, 0x03, 0xe8, + 0x61, 0x61, // value a + }, + {0xa2, // map with 2 keys with same major type + 0x19, 0x03, 0xe8, // key 1000 (out of order due to longer length) + 0x61, 0x61, //value "a" + + 0x0a, // key 10 + 0x61, 0x62}, // value "b" + {0xa2, // map with 2 text string keys + 0x62, 'a', 'a', // key text string "aa" + // (out of order due to longer length) + 0x02, + + 0x61, 'b', // key "b" + 0x01, + }, + {0xa2, // map with 2 byte string keys + 0x42, 'x', 'x', // key byte string "xx" + // (out of order due to longer length) + 0x02, + + 0x41, 'y', // key byte string "y" + 0x01, + }, + //clang-format on + }; + + int test_element_index = 0; + Reader::DecoderError error_code; + for (const auto& unsorted_map : kMapsWithUnsortedKeys) { + testing::Message scope_message; + scope_message << "testing unsorted map : " << test_element_index++; + SCOPED_TRACE(scope_message); + + base::Optional cbor = + Reader::Read(unsorted_map, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_KEY); + } +} + +TEST(CBORReaderTest, TestDuplicateKeyError) { + static const std::vector kMapWithDuplicateKey = { + // clang-format off + 0xa6, // map of 6 pairs: + 0x60, // "" + 0x61, 0x2e, // "." + + 0x61, 0x62, // "b" + 0x61, 0x42, // "B" + + 0x61, 0x62, // "b" (Duplicate key) + 0x61, 0x43, // "C" + + 0x61, 0x64, // "d" + 0x61, 0x44, // "D" + + 0x61, 0x65, // "e" + 0x61, 0x44, // "D" + + 0x62, 0x61, 0x61, // "aa" + 0x62, 0x41, 0x41, // "AA" + // clang-format on + }; + + Reader::DecoderError error_code; + + base::Optional cbor = Reader::Read(kMapWithDuplicateKey, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_KEY); +} + +// Leveraging Markus Kuhn’s UTF-8 decoder stress test. See +// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt for details. +TEST(CBORReaderTest, TestIncorrectStringEncodingError) { + static const std::vector utf8_character_encodings[] = { + // Corresponds to utf8 encoding of "퟿" (section 2.3.1 of stress test). + {0x63, 0xED, 0x9F, 0xBF}, + // Corresponds to utf8 encoding of "" (section 2.3.2 of stress test). + {0x63, 0xEE, 0x80, 0x80}, + // Corresponds to utf8 encoding of "�" (section 2.3.3 of stress test). + {0x63, 0xEF, 0xBF, 0xBD}, + }; + + int test_element_index = 0; + Reader::DecoderError error_code; + for (const auto& cbor_byte : utf8_character_encodings) { + SCOPED_TRACE(testing::Message() << "testing cbor data utf8 encoding : " + << test_element_index++); + + base::Optional correctly_encoded_cbor = + Reader::Read(cbor_byte, &error_code); + EXPECT_TRUE(correctly_encoded_cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR); + } + + // Incorrect UTF8 encoding referenced by section 3.5.3 of the stress test. + std::vector impossible_utf_byte{0x64, 0xfe, 0xfe, 0xff, 0xff}; + base::Optional incorrectly_encoded_cbor = + Reader::Read(impossible_utf_byte, &error_code); + EXPECT_FALSE(incorrectly_encoded_cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::INVALID_UTF8); +} + +TEST(CBORReaderTest, TestExtraneousCBORDataError) { + static const std::vector zero_padded_cbor_list[] = { + // 1 extra byte after a 2-byte unsigned int. + {0x19, 0x03, 0x05, 0x00}, + // 1 extra byte after a 4-byte cbor byte array. + {0x44, 0x01, 0x02, 0x03, 0x04, 0x00}, + // 1 extra byte after a 4-byte string. + {0x64, 0x49, 0x45, 0x54, 0x46, 0x00}, + // 1 extra byte after CBOR array of length 2. + {0x82, 0x01, 0x02, 0x00}, + // 1 extra key value pair after CBOR map of size 2. + {0xa1, 0x61, 0x63, 0x02, 0x61, 0x64, 0x03}, + }; + + int test_element_index = 0; + for (const auto& extraneous_cbor_data : zero_padded_cbor_list) { + SCOPED_TRACE(testing::Message() + << "testing cbor extraneous data : " << test_element_index++); + + Reader::DecoderError error_code; + base::Optional cbor = + Reader::Read(extraneous_cbor_data, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA); + } +} + +TEST(CBORReaderTest, TestUnsupportedSimpleValue) { + static const std::vector unsupported_simple_values[] = { + // Simple value (0, unassigned) + {0xE0}, + // Simple value (19, unassigned) + {0xF3}, + // Simple value (24, reserved) + {0xF8, 0x18}, + // Simple value (28, reserved) + {0xF8, 0x1C}, + // Simple value (29, reserved) + {0xF8, 0x1D}, + // Simple value (30, reserved) + {0xF8, 0x1E}, + // Simple value (31, reserved) + {0xF8, 0x1F}, + // Simple value (32, unassigned) + {0xF8, 0x20}, + // Simple value (255, unassigned) + {0xF8, 0xFF}, + }; + + for (const auto& unsupported_simple_val : unsupported_simple_values) { + SCOPED_TRACE(testing::Message() + << "testing unsupported cbor simple value : " + << ::testing::PrintToString(unsupported_simple_val)); + + Reader::DecoderError error_code; + base::Optional cbor = + Reader::Read(unsupported_simple_val, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::UNSUPPORTED_SIMPLE_VALUE); + } +} + +TEST(CBORReaderTest, TestSuperLongContentDontCrash) { + static const std::vector kTestCases[] = { + // CBOR array of 0xffffffff length. + {0x9b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + // CBOR map of 0xffffffff pairs. + {0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }; + for (const auto& test_case : kTestCases) { + Reader::DecoderError error_code; + base::Optional cbor = Reader::Read(test_case, &error_code); + EXPECT_FALSE(cbor.has_value()); + EXPECT_EQ(error_code, Reader::DecoderError::INCOMPLETE_CBOR_DATA); + } +} + +} // namespace cbor diff --git a/chromium/components/cbor/values.cc b/chromium/components/cbor/values.cc new file mode 100644 index 00000000000..f495a7fd152 --- /dev/null +++ b/chromium/components/cbor/values.cc @@ -0,0 +1,281 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/cbor/values.h" + +#include +#include + +#include "base/numerics/safe_conversions.h" +#include "base/strings/string_util.h" +#include "components/cbor/constants.h" + +namespace cbor { + +Value::Value() noexcept : type_(Type::NONE) {} + +Value::Value(Value&& that) noexcept { + InternalMoveConstructFrom(std::move(that)); +} + +Value::Value(Type type) : type_(type) { + // Initialize with the default value. + switch (type_) { + case Type::UNSIGNED: + case Type::NEGATIVE: + integer_value_ = 0; + return; + case Type::BYTE_STRING: + new (&bytestring_value_) BinaryValue(); + return; + case Type::STRING: + new (&string_value_) std::string(); + return; + case Type::ARRAY: + new (&array_value_) ArrayValue(); + return; + case Type::MAP: + new (&map_value_) MapValue(); + return; + case Type::TAG: + NOTREACHED() << constants::kUnsupportedMajorType; + return; + case Type::SIMPLE_VALUE: + simple_value_ = Value::SimpleValue::UNDEFINED; + return; + case Type::NONE: + return; + } + NOTREACHED(); +} + +Value::Value(SimpleValue in_simple) + : type_(Type::SIMPLE_VALUE), simple_value_(in_simple) { + CHECK(static_cast(in_simple) >= 20 && static_cast(in_simple) <= 23); +} + +Value::Value(bool boolean_value) : type_(Type::SIMPLE_VALUE) { + simple_value_ = boolean_value ? Value::SimpleValue::TRUE_VALUE + : Value::SimpleValue::FALSE_VALUE; +} + +Value::Value(int integer_value) + : Value(base::checked_cast(integer_value)) {} + +Value::Value(int64_t integer_value) : integer_value_(integer_value) { + type_ = integer_value >= 0 ? Type::UNSIGNED : Type::NEGATIVE; +} + +Value::Value(base::span in_bytes) + : type_(Type::BYTE_STRING), + bytestring_value_(in_bytes.begin(), in_bytes.end()) {} + +Value::Value(BinaryValue&& in_bytes) noexcept + : type_(Type::BYTE_STRING), bytestring_value_(std::move(in_bytes)) {} + +Value::Value(const char* in_string, Type type) + : Value(base::StringPiece(in_string), type) {} + +Value::Value(std::string&& in_string, Type type) noexcept : type_(type) { + switch (type_) { + case Type::STRING: + new (&string_value_) std::string(); + string_value_ = std::move(in_string); + DCHECK(base::IsStringUTF8(string_value_)); + break; + case Type::BYTE_STRING: + new (&bytestring_value_) BinaryValue(); + bytestring_value_ = BinaryValue(in_string.begin(), in_string.end()); + break; + default: + NOTREACHED(); + } +} + +Value::Value(base::StringPiece in_string, Type type) : type_(type) { + switch (type_) { + case Type::STRING: + new (&string_value_) std::string(); + string_value_ = in_string.as_string(); + DCHECK(base::IsStringUTF8(string_value_)); + break; + case Type::BYTE_STRING: + new (&bytestring_value_) BinaryValue(); + bytestring_value_ = BinaryValue(in_string.begin(), in_string.end()); + break; + default: + NOTREACHED(); + } +} + +Value::Value(const ArrayValue& in_array) : type_(Type::ARRAY), array_value_() { + array_value_.reserve(in_array.size()); + for (const auto& val : in_array) + array_value_.emplace_back(val.Clone()); +} + +Value::Value(ArrayValue&& in_array) noexcept + : type_(Type::ARRAY), array_value_(std::move(in_array)) {} + +Value::Value(const MapValue& in_map) : type_(Type::MAP), map_value_() { + map_value_.reserve(in_map.size()); + for (const auto& it : in_map) + map_value_.emplace_hint(map_value_.end(), it.first.Clone(), + it.second.Clone()); +} + +Value::Value(MapValue&& in_map) noexcept + : type_(Type::MAP), map_value_(std::move(in_map)) {} + +Value& Value::operator=(Value&& that) noexcept { + InternalCleanup(); + InternalMoveConstructFrom(std::move(that)); + + return *this; +} + +Value::~Value() { + InternalCleanup(); +} + +Value Value::Clone() const { + switch (type_) { + case Type::NONE: + return Value(); + case Type::UNSIGNED: + case Type::NEGATIVE: + return Value(integer_value_); + case Type::BYTE_STRING: + return Value(bytestring_value_); + case Type::STRING: + return Value(string_value_); + case Type::ARRAY: + return Value(array_value_); + case Type::MAP: + return Value(map_value_); + case Type::TAG: + NOTREACHED() << constants::kUnsupportedMajorType; + return Value(); + case Type::SIMPLE_VALUE: + return Value(simple_value_); + } + + NOTREACHED(); + return Value(); +} + +Value::SimpleValue Value::GetSimpleValue() const { + CHECK(is_simple()); + return simple_value_; +} + +bool Value::GetBool() const { + CHECK(is_bool()); + return simple_value_ == SimpleValue::TRUE_VALUE; +} + +const int64_t& Value::GetInteger() const { + CHECK(is_integer()); + return integer_value_; +} + +const int64_t& Value::GetUnsigned() const { + CHECK(is_unsigned()); + CHECK_GE(integer_value_, 0); + return integer_value_; +} + +const int64_t& Value::GetNegative() const { + CHECK(is_negative()); + CHECK_LT(integer_value_, 0); + return integer_value_; +} + +const std::string& Value::GetString() const { + CHECK(is_string()); + return string_value_; +} + +const Value::BinaryValue& Value::GetBytestring() const { + CHECK(is_bytestring()); + return bytestring_value_; +} + +base::StringPiece Value::GetBytestringAsString() const { + CHECK(is_bytestring()); + const auto& bytestring_value = GetBytestring(); + return base::StringPiece( + reinterpret_cast(bytestring_value.data()), + bytestring_value.size()); +} + +const Value::ArrayValue& Value::GetArray() const { + CHECK(is_array()); + return array_value_; +} + +const Value::MapValue& Value::GetMap() const { + CHECK(is_map()); + return map_value_; +} + +void Value::InternalMoveConstructFrom(Value&& that) { + type_ = that.type_; + + switch (type_) { + case Type::UNSIGNED: + case Type::NEGATIVE: + integer_value_ = that.integer_value_; + return; + case Type::BYTE_STRING: + new (&bytestring_value_) BinaryValue(std::move(that.bytestring_value_)); + return; + case Type::STRING: + new (&string_value_) std::string(std::move(that.string_value_)); + return; + case Type::ARRAY: + new (&array_value_) ArrayValue(std::move(that.array_value_)); + return; + case Type::MAP: + new (&map_value_) MapValue(std::move(that.map_value_)); + return; + case Type::TAG: + NOTREACHED() << constants::kUnsupportedMajorType; + return; + case Type::SIMPLE_VALUE: + simple_value_ = that.simple_value_; + return; + case Type::NONE: + return; + } + NOTREACHED(); +} + +void Value::InternalCleanup() { + switch (type_) { + case Type::BYTE_STRING: + bytestring_value_.~BinaryValue(); + break; + case Type::STRING: + string_value_.~basic_string(); + break; + case Type::ARRAY: + array_value_.~ArrayValue(); + break; + case Type::MAP: + map_value_.~MapValue(); + break; + case Type::TAG: + NOTREACHED() << constants::kUnsupportedMajorType; + break; + case Type::NONE: + case Type::UNSIGNED: + case Type::NEGATIVE: + case Type::SIMPLE_VALUE: + break; + } + type_ = Type::NONE; +} + +} // namespace cbor diff --git a/chromium/components/cbor/values.h b/chromium/components/cbor/values.h new file mode 100644 index 00000000000..ed9aae23fad --- /dev/null +++ b/chromium/components/cbor/values.h @@ -0,0 +1,190 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CBOR_VALUES_H_ +#define COMPONENTS_CBOR_VALUES_H_ + +#include + +#include +#include +#include + +#include "base/containers/flat_map.h" +#include "base/containers/span.h" +#include "base/macros.h" +#include "base/strings/string_piece.h" +#include "components/cbor/cbor_export.h" + +namespace cbor { + +// A class for Concise Binary Object Representation (CBOR) values. +// This does not support: +// * Floating-point numbers. +// * Indefinite-length encodings. +class CBOR_EXPORT Value { + public: + struct Less { + // Comparison predicate to order keys in a dictionary as required by the + // canonical CBOR order defined in + // https://tools.ietf.org/html/rfc7049#section-3.9 + // TODO(808022): Clarify where this stands. + bool operator()(const Value& a, const Value& b) const { + // The current implementation only supports integer, text string, + // and byte string keys. + DCHECK((a.is_integer() || a.is_string() || a.is_bytestring()) && + (b.is_integer() || b.is_string() || b.is_bytestring())); + + // Below text from https://tools.ietf.org/html/rfc7049 errata 4409: + // * If the major types are different, the one with the lower value + // in numerical order sorts earlier. + if (a.type() != b.type()) + return a.type() < b.type(); + + // * If two keys have different lengths, the shorter one sorts + // earlier; + // * If two keys have the same length, the one with the lower value + // in (byte-wise) lexical order sorts earlier. + switch (a.type()) { + case Type::UNSIGNED: + // For unsigned integers, the smaller value has shorter length, + // and (byte-wise) lexical representation. + return a.GetInteger() < b.GetInteger(); + case Type::NEGATIVE: + // For negative integers, the value closer to zero has shorter length, + // and (byte-wise) lexical representation. + return a.GetInteger() > b.GetInteger(); + case Type::STRING: { + const auto& a_str = a.GetString(); + const size_t a_length = a_str.size(); + const auto& b_str = b.GetString(); + const size_t b_length = b_str.size(); + return std::tie(a_length, a_str) < std::tie(b_length, b_str); + } + case Type::BYTE_STRING: { + const auto& a_str = a.GetBytestring(); + const size_t a_length = a_str.size(); + const auto& b_str = b.GetBytestring(); + const size_t b_length = b_str.size(); + return std::tie(a_length, a_str) < std::tie(b_length, b_str); + } + default: + break; + } + + NOTREACHED(); + return false; + } + + using is_transparent = void; + }; + + using BinaryValue = std::vector; + using ArrayValue = std::vector; + using MapValue = base::flat_map; + + enum class Type { + UNSIGNED = 0, + NEGATIVE = 1, + BYTE_STRING = 2, + STRING = 3, + ARRAY = 4, + MAP = 5, + TAG = 6, + SIMPLE_VALUE = 7, + NONE = -1, + }; + + enum class SimpleValue { + FALSE_VALUE = 20, + TRUE_VALUE = 21, + NULL_VALUE = 22, + UNDEFINED = 23, + }; + + Value(Value&& that) noexcept; + Value() noexcept; // A NONE value. + + explicit Value(Type type); + + explicit Value(SimpleValue in_simple); + explicit Value(bool boolean_value); + + explicit Value(int integer_value); + explicit Value(int64_t integer_value); + explicit Value(uint64_t integer_value) = delete; + + explicit Value(base::span in_bytes); + explicit Value(BinaryValue&& in_bytes) noexcept; + + explicit Value(const char* in_string, Type type = Type::STRING); + explicit Value(std::string&& in_string, Type type = Type::STRING) noexcept; + explicit Value(base::StringPiece in_string, Type type = Type::STRING); + + explicit Value(const ArrayValue& in_array); + explicit Value(ArrayValue&& in_array) noexcept; + + explicit Value(const MapValue& in_map); + explicit Value(MapValue&& in_map) noexcept; + + Value& operator=(Value&& that) noexcept; + + ~Value(); + + // Value's copy constructor and copy assignment operator are deleted. + // Use this to obtain a deep copy explicitly. + Value Clone() const; + + // Returns the type of the value stored by the current Value object. + Type type() const { return type_; } + + // Returns true if the current object represents a given type. + bool is_type(Type type) const { return type == type_; } + bool is_none() const { return type() == Type::NONE; } + bool is_simple() const { return type() == Type::SIMPLE_VALUE; } + bool is_bool() const { + return is_simple() && (simple_value_ == SimpleValue::TRUE_VALUE || + simple_value_ == SimpleValue::FALSE_VALUE); + } + bool is_unsigned() const { return type() == Type::UNSIGNED; } + bool is_negative() const { return type() == Type::NEGATIVE; } + bool is_integer() const { return is_unsigned() || is_negative(); } + bool is_bytestring() const { return type() == Type::BYTE_STRING; } + bool is_string() const { return type() == Type::STRING; } + bool is_array() const { return type() == Type::ARRAY; } + bool is_map() const { return type() == Type::MAP; } + + // These will all fatally assert if the type doesn't match. + SimpleValue GetSimpleValue() const; + bool GetBool() const; + const int64_t& GetInteger() const; + const int64_t& GetUnsigned() const; + const int64_t& GetNegative() const; + const BinaryValue& GetBytestring() const; + base::StringPiece GetBytestringAsString() const; + // Returned string may contain NUL characters. + const std::string& GetString() const; + const ArrayValue& GetArray() const; + const MapValue& GetMap() const; + + private: + Type type_; + + union { + SimpleValue simple_value_; + int64_t integer_value_; + BinaryValue bytestring_value_; + std::string string_value_; + ArrayValue array_value_; + MapValue map_value_; + }; + + void InternalMoveConstructFrom(Value&& that); + void InternalCleanup(); + + DISALLOW_COPY_AND_ASSIGN(Value); +}; +} // namespace cbor + +#endif // COMPONENTS_CBOR_VALUES_H_ diff --git a/chromium/components/cbor/values_unittest.cc b/chromium/components/cbor/values_unittest.cc new file mode 100644 index 00000000000..1276b998103 --- /dev/null +++ b/chromium/components/cbor/values_unittest.cc @@ -0,0 +1,369 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/cbor/values.h" + +#include +#include + +#include "testing/gtest/include/gtest/gtest.h" + +namespace cbor { + +TEST(CBORValuesTest, TestNothrow) { + static_assert(std::is_nothrow_move_constructible::value, + "IsNothrowMoveConstructible"); + static_assert(std::is_nothrow_default_constructible::value, + "IsNothrowDefaultConstructible"); + static_assert(std::is_nothrow_constructible::value, + "IsNothrowMoveConstructibleFromString"); + static_assert( + std::is_nothrow_constructible::value, + "IsNothrowMoveConstructibleFromBytestring"); + static_assert( + std::is_nothrow_constructible::value, + "IsNothrowMoveConstructibleFromArray"); + static_assert(std::is_nothrow_move_assignable::value, + "IsNothrowMoveAssignable"); +} + +// Test constructors +TEST(CBORValuesTest, ConstructUnsigned) { + Value value(37); + ASSERT_EQ(Value::Type::UNSIGNED, value.type()); + EXPECT_EQ(37u, value.GetInteger()); +} + +TEST(CBORValuesTest, ConstructNegative) { + Value value(-1); + ASSERT_EQ(Value::Type::NEGATIVE, value.type()); + EXPECT_EQ(-1, value.GetInteger()); +} + +TEST(CBORValuesTest, ConstructStringFromConstCharPtr) { + const char* str = "foobar"; + Value value(str); + ASSERT_EQ(Value::Type::STRING, value.type()); + EXPECT_EQ("foobar", value.GetString()); +} + +TEST(CBORValuesTest, ConstructStringFromStdStringConstRef) { + std::string str = "foobar"; + Value value(str); + ASSERT_EQ(Value::Type::STRING, value.type()); + EXPECT_EQ("foobar", value.GetString()); +} + +TEST(CBORValuesTest, ConstructStringFromStdStringRefRef) { + std::string str = "foobar"; + Value value(std::move(str)); + ASSERT_EQ(Value::Type::STRING, value.type()); + EXPECT_EQ("foobar", value.GetString()); +} + +TEST(CBORValuesTest, ConstructBytestring) { + Value value(Value::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2})); + ASSERT_EQ(Value::Type::BYTE_STRING, value.type()); + EXPECT_EQ(Value::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}), + value.GetBytestring()); +} + +TEST(CBORValuesTest, ConstructBytestringFromString) { + Value value(Value("hello", Value::Type::BYTE_STRING)); + ASSERT_EQ(Value::Type::BYTE_STRING, value.type()); + EXPECT_EQ(Value::BinaryValue({'h', 'e', 'l', 'l', 'o'}), + value.GetBytestring()); + EXPECT_EQ("hello", value.GetBytestringAsString()); +} + +TEST(CBORValuesTest, ConstructArray) { + Value::ArrayValue array; + array.emplace_back(Value("foo")); + { + Value value(array); + ASSERT_EQ(Value::Type::ARRAY, value.type()); + ASSERT_EQ(1u, value.GetArray().size()); + ASSERT_EQ(Value::Type::STRING, value.GetArray()[0].type()); + EXPECT_EQ("foo", value.GetArray()[0].GetString()); + } + + array.back() = Value("bar"); + { + Value value(std::move(array)); + ASSERT_EQ(Value::Type::ARRAY, value.type()); + ASSERT_EQ(1u, value.GetArray().size()); + ASSERT_EQ(Value::Type::STRING, value.GetArray()[0].type()); + EXPECT_EQ("bar", value.GetArray()[0].GetString()); + } +} + +TEST(CBORValuesTest, ConstructMap) { + Value::MapValue map; + const Value key_foo("foo"); + map[Value("foo")] = Value("bar"); + { + Value value(map); + ASSERT_EQ(Value::Type::MAP, value.type()); + ASSERT_EQ(value.GetMap().count(key_foo), 1u); + ASSERT_EQ(Value::Type::STRING, value.GetMap().find(key_foo)->second.type()); + EXPECT_EQ("bar", value.GetMap().find(key_foo)->second.GetString()); + } + + map[Value("foo")] = Value("baz"); + { + Value value(std::move(map)); + ASSERT_EQ(Value::Type::MAP, value.type()); + ASSERT_EQ(value.GetMap().count(key_foo), 1u); + ASSERT_EQ(Value::Type::STRING, value.GetMap().find(key_foo)->second.type()); + EXPECT_EQ("baz", value.GetMap().find(key_foo)->second.GetString()); + } +} + +TEST(CBORValuesTest, ConstructSimpleValue) { + Value false_value(Value::SimpleValue::FALSE_VALUE); + ASSERT_EQ(Value::Type::SIMPLE_VALUE, false_value.type()); + EXPECT_EQ(Value::SimpleValue::FALSE_VALUE, false_value.GetSimpleValue()); + + Value true_value(Value::SimpleValue::TRUE_VALUE); + ASSERT_EQ(Value::Type::SIMPLE_VALUE, true_value.type()); + EXPECT_EQ(Value::SimpleValue::TRUE_VALUE, true_value.GetSimpleValue()); + + Value null_value(Value::SimpleValue::NULL_VALUE); + ASSERT_EQ(Value::Type::SIMPLE_VALUE, null_value.type()); + EXPECT_EQ(Value::SimpleValue::NULL_VALUE, null_value.GetSimpleValue()); + + Value undefined_value(Value::SimpleValue::UNDEFINED); + ASSERT_EQ(Value::Type::SIMPLE_VALUE, undefined_value.type()); + EXPECT_EQ(Value::SimpleValue::UNDEFINED, undefined_value.GetSimpleValue()); +} + +TEST(CBORValuesTest, ConstructSimpleBooleanValue) { + Value true_value(true); + ASSERT_EQ(Value::Type::SIMPLE_VALUE, true_value.type()); + EXPECT_TRUE(true_value.GetBool()); + + Value false_value(false); + ASSERT_EQ(Value::Type::SIMPLE_VALUE, false_value.type()); + EXPECT_FALSE(false_value.GetBool()); +} + +// Test copy constructors +TEST(CBORValuesTest, CopyUnsigned) { + Value value(74); + Value copied_value(value.Clone()); + ASSERT_EQ(value.type(), copied_value.type()); + EXPECT_EQ(value.GetInteger(), copied_value.GetInteger()); + + Value blank; + + blank = value.Clone(); + ASSERT_EQ(value.type(), blank.type()); + EXPECT_EQ(value.GetInteger(), blank.GetInteger()); +} + +TEST(CBORValuesTest, CopyNegativeInt) { + Value value(-74); + Value copied_value(value.Clone()); + ASSERT_EQ(value.type(), copied_value.type()); + EXPECT_EQ(value.GetInteger(), copied_value.GetInteger()); + + Value blank; + + blank = value.Clone(); + ASSERT_EQ(value.type(), blank.type()); + EXPECT_EQ(value.GetInteger(), blank.GetInteger()); +} + +TEST(CBORValuesTest, CopyString) { + Value value("foobar"); + Value copied_value(value.Clone()); + ASSERT_EQ(value.type(), copied_value.type()); + EXPECT_EQ(value.GetString(), copied_value.GetString()); + + Value blank; + + blank = value.Clone(); + ASSERT_EQ(value.type(), blank.type()); + EXPECT_EQ(value.GetString(), blank.GetString()); +} + +TEST(CBORValuesTest, CopyBytestring) { + Value value(Value::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2})); + Value copied_value(value.Clone()); + ASSERT_EQ(value.type(), copied_value.type()); + EXPECT_EQ(value.GetBytestring(), copied_value.GetBytestring()); + + Value blank; + + blank = value.Clone(); + ASSERT_EQ(value.type(), blank.type()); + EXPECT_EQ(value.GetBytestring(), blank.GetBytestring()); +} + +TEST(CBORValuesTest, CopyArray) { + Value::ArrayValue array; + array.emplace_back(123); + Value value(std::move(array)); + + Value copied_value(value.Clone()); + ASSERT_EQ(1u, copied_value.GetArray().size()); + ASSERT_TRUE(copied_value.GetArray()[0].is_unsigned()); + EXPECT_EQ(value.GetArray()[0].GetInteger(), + copied_value.GetArray()[0].GetInteger()); + + Value blank; + blank = value.Clone(); + EXPECT_EQ(1u, blank.GetArray().size()); +} + +TEST(CBORValuesTest, CopyMap) { + Value::MapValue map; + Value key_a("a"); + map[Value("a")] = Value(123); + Value value(std::move(map)); + + Value copied_value(value.Clone()); + EXPECT_EQ(1u, copied_value.GetMap().size()); + ASSERT_EQ(value.GetMap().count(key_a), 1u); + ASSERT_EQ(copied_value.GetMap().count(key_a), 1u); + ASSERT_TRUE(copied_value.GetMap().find(key_a)->second.is_unsigned()); + EXPECT_EQ(value.GetMap().find(key_a)->second.GetInteger(), + copied_value.GetMap().find(key_a)->second.GetInteger()); + + Value blank; + blank = value.Clone(); + EXPECT_EQ(1u, blank.GetMap().size()); + ASSERT_EQ(blank.GetMap().count(key_a), 1u); + ASSERT_TRUE(blank.GetMap().find(key_a)->second.is_unsigned()); + EXPECT_EQ(value.GetMap().find(key_a)->second.GetInteger(), + blank.GetMap().find(key_a)->second.GetInteger()); +} + +TEST(CBORValuesTest, CopySimpleValue) { + Value value(Value::SimpleValue::TRUE_VALUE); + Value copied_value(value.Clone()); + EXPECT_EQ(value.type(), copied_value.type()); + EXPECT_EQ(value.GetSimpleValue(), copied_value.GetSimpleValue()); + + Value blank; + + blank = value.Clone(); + EXPECT_EQ(value.type(), blank.type()); + EXPECT_EQ(value.GetSimpleValue(), blank.GetSimpleValue()); +} + +// Test move constructors and move-assignment +TEST(CBORValuesTest, MoveUnsigned) { + Value value(74); + Value moved_value(std::move(value)); + EXPECT_EQ(Value::Type::UNSIGNED, moved_value.type()); + EXPECT_EQ(74u, moved_value.GetInteger()); + + Value blank; + + blank = Value(654); + EXPECT_EQ(Value::Type::UNSIGNED, blank.type()); + EXPECT_EQ(654u, blank.GetInteger()); +} + +TEST(CBORValuesTest, MoveNegativeInteger) { + Value value(-74); + Value moved_value(std::move(value)); + EXPECT_EQ(Value::Type::NEGATIVE, moved_value.type()); + EXPECT_EQ(-74, moved_value.GetInteger()); + + Value blank; + + blank = Value(-654); + EXPECT_EQ(Value::Type::NEGATIVE, blank.type()); + EXPECT_EQ(-654, blank.GetInteger()); +} + +TEST(CBORValuesTest, MoveString) { + Value value("foobar"); + Value moved_value(std::move(value)); + EXPECT_EQ(Value::Type::STRING, moved_value.type()); + EXPECT_EQ("foobar", moved_value.GetString()); + + Value blank; + + blank = Value("foobar"); + EXPECT_EQ(Value::Type::STRING, blank.type()); + EXPECT_EQ("foobar", blank.GetString()); +} + +TEST(CBORValuesTest, MoveBytestring) { + const Value::BinaryValue bytes({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}); + Value value(bytes); + Value moved_value(std::move(value)); + EXPECT_EQ(Value::Type::BYTE_STRING, moved_value.type()); + EXPECT_EQ(bytes, moved_value.GetBytestring()); + + Value blank; + + blank = Value(bytes); + EXPECT_EQ(Value::Type::BYTE_STRING, blank.type()); + EXPECT_EQ(bytes, blank.GetBytestring()); +} + +TEST(CBORValuesTest, MoveConstructMap) { + Value::MapValue map; + const Value key_a("a"); + map[Value("a")] = Value(123); + + Value value(std::move(map)); + Value moved_value(std::move(value)); + ASSERT_EQ(Value::Type::MAP, moved_value.type()); + ASSERT_EQ(moved_value.GetMap().count(key_a), 1u); + ASSERT_TRUE(moved_value.GetMap().find(key_a)->second.is_unsigned()); + EXPECT_EQ(123u, moved_value.GetMap().find(key_a)->second.GetInteger()); +} + +TEST(CBORValuesTest, MoveAssignMap) { + Value::MapValue map; + const Value key_a("a"); + map[Value("a")] = Value(123); + + Value blank; + blank = Value(std::move(map)); + ASSERT_TRUE(blank.is_map()); + ASSERT_EQ(blank.GetMap().count(key_a), 1u); + ASSERT_TRUE(blank.GetMap().find(key_a)->second.is_unsigned()); + EXPECT_EQ(123u, blank.GetMap().find(key_a)->second.GetInteger()); +} + +TEST(CBORValuesTest, MoveArray) { + Value::ArrayValue array; + array.emplace_back(123); + Value value(array); + Value moved_value(std::move(value)); + EXPECT_EQ(Value::Type::ARRAY, moved_value.type()); + EXPECT_EQ(123u, moved_value.GetArray().back().GetInteger()); + + Value blank; + blank = Value(std::move(array)); + EXPECT_EQ(Value::Type::ARRAY, blank.type()); + EXPECT_EQ(123u, blank.GetArray().back().GetInteger()); +} + +TEST(CBORValuesTest, MoveSimpleValue) { + Value value(Value::SimpleValue::UNDEFINED); + Value moved_value(std::move(value)); + EXPECT_EQ(Value::Type::SIMPLE_VALUE, moved_value.type()); + EXPECT_EQ(Value::SimpleValue::UNDEFINED, moved_value.GetSimpleValue()); + + Value blank; + + blank = Value(Value::SimpleValue::UNDEFINED); + EXPECT_EQ(Value::Type::SIMPLE_VALUE, blank.type()); + EXPECT_EQ(Value::SimpleValue::UNDEFINED, blank.GetSimpleValue()); +} + +TEST(CBORValuesTest, SelfSwap) { + Value test(1); + std::swap(test, test); + EXPECT_EQ(test.GetInteger(), 1u); +} + +} // namespace cbor diff --git a/chromium/components/cbor/writer.cc b/chromium/components/cbor/writer.cc new file mode 100644 index 00000000000..a522eff4e2b --- /dev/null +++ b/chromium/components/cbor/writer.cc @@ -0,0 +1,179 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/cbor/writer.h" + +#include + +#include "base/numerics/safe_conversions.h" +#include "base/strings/string_piece.h" +#include "components/cbor/constants.h" + +namespace cbor { + +Writer::~Writer() {} + +// static +base::Optional> Writer::Write(const Value& node, + size_t max_nesting_level) { + std::vector cbor; + Writer writer(&cbor); + if (writer.EncodeCBOR(node, base::checked_cast(max_nesting_level))) + return cbor; + return base::nullopt; +} + +Writer::Writer(std::vector* cbor) : encoded_cbor_(cbor) {} + +bool Writer::EncodeCBOR(const Value& node, int max_nesting_level) { + if (max_nesting_level < 0) + return false; + + switch (node.type()) { + case Value::Type::NONE: { + StartItem(Value::Type::BYTE_STRING, 0); + return true; + } + + // Represents unsigned integers. + case Value::Type::UNSIGNED: { + int64_t value = node.GetUnsigned(); + StartItem(Value::Type::UNSIGNED, static_cast(value)); + return true; + } + + // Represents negative integers. + case Value::Type::NEGATIVE: { + int64_t value = node.GetNegative(); + StartItem(Value::Type::NEGATIVE, static_cast(-(value + 1))); + return true; + } + + // Represents a byte string. + case Value::Type::BYTE_STRING: { + const Value::BinaryValue& bytes = node.GetBytestring(); + StartItem(Value::Type::BYTE_STRING, + base::strict_cast(bytes.size())); + // Add the bytes. + encoded_cbor_->insert(encoded_cbor_->end(), bytes.begin(), bytes.end()); + return true; + } + + case Value::Type::STRING: { + base::StringPiece string = node.GetString(); + StartItem(Value::Type::STRING, + base::strict_cast(string.size())); + + // Add the characters. + encoded_cbor_->insert(encoded_cbor_->end(), string.begin(), string.end()); + return true; + } + + // Represents an array. + case Value::Type::ARRAY: { + const Value::ArrayValue& array = node.GetArray(); + StartItem(Value::Type::ARRAY, array.size()); + for (const auto& value : array) { + if (!EncodeCBOR(value, max_nesting_level - 1)) + return false; + } + return true; + } + + // Represents a map. + case Value::Type::MAP: { + const Value::MapValue& map = node.GetMap(); + StartItem(Value::Type::MAP, map.size()); + + for (const auto& value : map) { + if (!EncodeCBOR(value.first, max_nesting_level - 1)) + return false; + if (!EncodeCBOR(value.second, max_nesting_level - 1)) + return false; + } + return true; + } + + case Value::Type::TAG: + NOTREACHED() << constants::kUnsupportedMajorType; + return false; + + // Represents a simple value. + case Value::Type::SIMPLE_VALUE: { + const Value::SimpleValue simple_value = node.GetSimpleValue(); + StartItem(Value::Type::SIMPLE_VALUE, + base::checked_cast(simple_value)); + return true; + } + } + + // This is needed because, otherwise, MSVC complains that not all paths return + // a value. We should be able to remove it once MSVC builders are gone. + NOTREACHED(); + return false; +} + +void Writer::StartItem(Value::Type type, uint64_t size) { + encoded_cbor_->push_back(base::checked_cast( + static_cast(type) << constants::kMajorTypeBitShift)); + SetUint(size); +} + +void Writer::SetAdditionalInformation(uint8_t additional_information) { + DCHECK(!encoded_cbor_->empty()); + DCHECK_EQ(additional_information & constants::kAdditionalInformationMask, + additional_information); + encoded_cbor_->back() |= + (additional_information & constants::kAdditionalInformationMask); +} + +void Writer::SetUint(uint64_t value) { + size_t count = GetNumUintBytes(value); + int shift = -1; + // Values under 24 are encoded directly in the initial byte. + // Otherwise, the last 5 bits of the initial byte contains the length + // of unsigned integer, which is encoded in following bytes. + switch (count) { + case 0: + SetAdditionalInformation(base::checked_cast(value)); + break; + case 1: + SetAdditionalInformation(constants::kAdditionalInformation1Byte); + shift = 0; + break; + case 2: + SetAdditionalInformation(constants::kAdditionalInformation2Bytes); + shift = 1; + break; + case 4: + SetAdditionalInformation(constants::kAdditionalInformation4Bytes); + shift = 3; + break; + case 8: + SetAdditionalInformation(constants::kAdditionalInformation8Bytes); + shift = 7; + break; + default: + NOTREACHED(); + break; + } + for (; shift >= 0; shift--) { + encoded_cbor_->push_back(0xFF & (value >> (shift * 8))); + } +} + +size_t Writer::GetNumUintBytes(uint64_t value) { + if (value < 24) { + return 0; + } else if (value <= 0xFF) { + return 1; + } else if (value <= 0xFFFF) { + return 2; + } else if (value <= 0xFFFFFFFF) { + return 4; + } + return 8; +} + +} // namespace cbor diff --git a/chromium/components/cbor/writer.h b/chromium/components/cbor/writer.h new file mode 100644 index 00000000000..39cd430a2b4 --- /dev/null +++ b/chromium/components/cbor/writer.h @@ -0,0 +1,100 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CBOR_WRITER_H_ +#define COMPONENTS_CBOR_WRITER_H_ + +#include +#include +#include + +#include "base/optional.h" +#include "components/cbor/cbor_export.h" +#include "components/cbor/values.h" + +// A basic Concise Binary Object Representation (CBOR) encoder as defined by +// https://tools.ietf.org/html/rfc7049. This is a generic encoder that supplies +// canonical, well-formed CBOR values but does not guarantee their validity +// (see https://tools.ietf.org/html/rfc7049#section-3.2). +// Supported: +// * Major types: +// * 0: Unsigned integers, up to INT64_MAX. +// * 1: Negative integers, to INT64_MIN. +// * 2: Byte strings. +// * 3: UTF-8 strings. +// * 4: Arrays, with the number of elements known at the start. +// * 5: Maps, with the number of elements known at the start +// of the container. +// * 7: Simple values. +// +// Unsupported: +// * Floating-point numbers. +// * Indefinite-length encodings. +// * Parsing. +// +// Requirements for canonical CBOR as suggested by RFC 7049 are: +// 1) All major data types for the CBOR values must be as short as possible. +// * Unsigned integer between 0 to 23 must be expressed in same byte as +// the major type. +// * 24 to 255 must be expressed only with an additional uint8_t. +// * 256 to 65535 must be expressed only with an additional uint16_t. +// * 65536 to 4294967295 must be expressed only with an additional +// uint32_t. * The rules for expression of length in major types +// 2 to 5 follow the above rule for integers. +// 2) Keys in every map must be sorted (first by major type, then by key +// length, then by value in byte-wise lexical order). +// 3) Indefinite length items must be converted to definite length items. +// 4) All maps must not have duplicate keys. +// +// Current implementation of Writer encoder meets all the requirements of +// canonical CBOR. + +namespace cbor { + +class CBOR_EXPORT Writer { + public: + // Default that should be sufficiently large for most use cases. + static constexpr size_t kDefaultMaxNestingDepth = 16; + + ~Writer(); + + // Returns the CBOR byte string representation of |node|, unless its nesting + // depth is greater than |max_nesting_depth|, in which case an empty optional + // value is returned. The nesting depth of |node| is defined as the number of + // arrays/maps that has to be traversed to reach the most nested Value + // contained in |node|. Primitive values and empty containers have nesting + // depths of 0. + static base::Optional> Write( + const Value& node, + size_t max_nesting_level = kDefaultMaxNestingDepth); + + private: + explicit Writer(std::vector* cbor); + + // Called recursively to build the CBOR bytestring. When completed, + // |encoded_cbor_| will contain the CBOR. + bool EncodeCBOR(const Value& node, int max_nesting_level); + + // Encodes the type and size of the data being added. + void StartItem(Value::Type type, uint64_t size); + + // Encodes the additional information for the data. + void SetAdditionalInformation(uint8_t additional_information); + + // Encodes an unsigned integer value. This is used to both write + // unsigned integers and to encode the lengths of other major types. + void SetUint(uint64_t value); + + // Get the number of bytes needed to store the unsigned integer. + size_t GetNumUintBytes(uint64_t value); + + // Holds the encoded CBOR data. + std::vector* encoded_cbor_; + + DISALLOW_COPY_AND_ASSIGN(Writer); +}; + +} // namespace cbor + +#endif // COMPONENTS_CBOR_WRITER_H_ diff --git a/chromium/components/cbor/writer_unittest.cc b/chromium/components/cbor/writer_unittest.cc new file mode 100644 index 00000000000..3fb96884373 --- /dev/null +++ b/chromium/components/cbor/writer_unittest.cc @@ -0,0 +1,489 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/cbor/writer.h" + +#include +#include + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +/* Leveraging RFC 7049 examples from + https://github.com/cbor/test-vectors/blob/master/appendix_a.json. */ +namespace cbor { + +TEST(CBORWriterTest, TestWriteUint) { + typedef struct { + const int64_t value; + const base::StringPiece cbor; + } UintTestCase; + + static const UintTestCase kUintTestCases[] = { + // Reminder: must specify length when creating string pieces + // with null bytes, else the string will truncate prematurely. + {0, base::StringPiece("\x00", 1)}, + {1, base::StringPiece("\x01")}, + {10, base::StringPiece("\x0a")}, + {23, base::StringPiece("\x17")}, + {24, base::StringPiece("\x18\x18")}, + {25, base::StringPiece("\x18\x19")}, + {100, base::StringPiece("\x18\x64")}, + {1000, base::StringPiece("\x19\x03\xe8")}, + {1000000, base::StringPiece("\x1a\x00\x0f\x42\x40", 5)}, + {0xFFFFFFFF, base::StringPiece("\x1a\xff\xff\xff\xff")}, + {0x100000000, + base::StringPiece("\x1b\x00\x00\x00\x01\x00\x00\x00\x00", 9)}, + {std::numeric_limits::max(), + base::StringPiece("\x1b\x7f\xff\xff\xff\xff\xff\xff\xff")}}; + + for (const UintTestCase& test_case : kUintTestCases) { + auto cbor = Writer::Write(Value(test_case.value)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); + } +} + +TEST(CBORWriterTest, TestWriteNegativeInteger) { + static const struct { + const int64_t negative_int; + const base::StringPiece cbor; + } kNegativeIntTestCases[] = { + {-1LL, base::StringPiece("\x20")}, + {-10LL, base::StringPiece("\x29")}, + {-23LL, base::StringPiece("\x36")}, + {-24LL, base::StringPiece("\x37")}, + {-25LL, base::StringPiece("\x38\x18")}, + {-100LL, base::StringPiece("\x38\x63")}, + {-1000LL, base::StringPiece("\x39\x03\xe7")}, + {-4294967296LL, base::StringPiece("\x3a\xff\xff\xff\xff")}, + {-4294967297LL, + base::StringPiece("\x3b\x00\x00\x00\x01\x00\x00\x00\x00", 9)}, + {std::numeric_limits::min(), + base::StringPiece("\x3b\x7f\xff\xff\xff\xff\xff\xff\xff")}, + }; + + for (const auto& test_case : kNegativeIntTestCases) { + SCOPED_TRACE(testing::Message() << "testing negative int at index: " + << test_case.negative_int); + + auto cbor = Writer::Write(Value(test_case.negative_int)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); + } +} + +TEST(CBORWriterTest, TestWriteBytes) { + typedef struct { + const std::vector bytes; + const base::StringPiece cbor; + } BytesTestCase; + + static const BytesTestCase kBytesTestCases[] = { + {{}, base::StringPiece("\x40")}, + {{0x01, 0x02, 0x03, 0x04}, base::StringPiece("\x44\x01\x02\x03\x04")}, + }; + + for (const BytesTestCase& test_case : kBytesTestCases) { + auto cbor = Writer::Write(Value(test_case.bytes)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); + } +} + +TEST(CBORWriterTest, TestWriteString) { + typedef struct { + const std::string string; + const base::StringPiece cbor; + } StringTestCase; + + static const StringTestCase kStringTestCases[] = { + {"", base::StringPiece("\x60")}, + {"a", base::StringPiece("\x61\x61")}, + {"IETF", base::StringPiece("\x64\x49\x45\x54\x46")}, + {"\"\\", base::StringPiece("\x62\x22\x5c")}, + {"\xc3\xbc", base::StringPiece("\x62\xc3\xbc")}, + {"\xe6\xb0\xb4", base::StringPiece("\x63\xe6\xb0\xb4")}, + {"\xf0\x90\x85\x91", base::StringPiece("\x64\xf0\x90\x85\x91")}}; + + for (const StringTestCase& test_case : kStringTestCases) { + SCOPED_TRACE(testing::Message() + << "testing encoding string : " << test_case.string); + + auto cbor = Writer::Write(Value(test_case.string)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); + } +} + +TEST(CBORWriterTest, TestWriteArray) { + static const uint8_t kArrayTestCaseCbor[] = { + // clang-format off + 0x98, 0x19, // array of 25 elements + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x18, 0x18, 0x19, + // clang-format on + }; + std::vector array; + for (int64_t i = 1; i <= 25; i++) { + array.push_back(Value(i)); + } + auto cbor = Writer::Write(Value(array)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), + testing::ElementsAreArray(kArrayTestCaseCbor, + arraysize(kArrayTestCaseCbor))); +} + +TEST(CBORWriterTest, TestWriteMap) { + static const uint8_t kMapTestCaseCbor[] = { + // clang-format off + 0xb8, 0x19, // map of 25 pairs: + 0x00, // key 0 + 0x61, 0x61, // value "a" + + 0x17, // key 23 + 0x61, 0x62, // value "b" + + 0x18, 0x18, // key 24 + 0x61, 0x63, // value "c" + + 0x18, 0xFF, // key 255 + 0x61, 0x64, // value "d" + + 0x19, 0x01, 0x00, // key 256 + 0x61, 0x65, // value "e" + + 0x19, 0xFF, 0xFF, // key 65535 + 0x61, 0x66, // value "f" + + 0x1A, 0x00, 0x01, 0x00, 0x00, // key 65536 + 0x61, 0x67, // value "g" + + 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, // key 4294967295 + 0x61, 0x68, // value "h" + + // key 4294967296 + 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x61, 0x69, // value "i" + + // key INT64_MAX + 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x61, 0x6a, // value "j" + + 0x20, // key -1 + 0x61, 0x6b, // value "k" + + 0x37, // key -24 + 0x61, 0x6c, // value "l" + + 0x38, 0x18, // key -25 + 0x61, 0x6d, // value "m" + + 0x38, 0xFF, // key -256 + 0x61, 0x6e, // value "n" + + 0x39, 0x01, 0x00, // key -257 + 0x61, 0x6f, // value "o" + + 0x3A, 0x00, 0x01, 0x00, 0x00, // key -65537 + 0x61, 0x70, // value "p" + + 0x3A, 0xFF, 0xFF, 0xFF, 0xFF, // key -4294967296 + 0x61, 0x71, // value "q" + + // key -4294967297 + 0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x61, 0x72, // value "r" + + // key INT64_MIN + 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x61, 0x73, // value "s" + + 0x41, 'a', // byte string "a" + 0x02, + + 0x43, 'b', 'a', 'r', // byte string "bar" + 0x03, + + 0x43, 'f', 'o', 'o', // byte string "foo" + 0x04, + + 0x60, // key "" + 0x61, 0x2e, // value "." + + 0x61, 0x65, // key "e" + 0x61, 0x45, // value "E" + + 0x62, 0x61, 0x61, // key "aa" + 0x62, 0x41, 0x41, // value "AA" + // clang-format on + }; + Value::MapValue map; + // Shorter strings sort first in CTAP, thus the “aa” value should be + // serialised last in the map. + map[Value("aa")] = Value("AA"); + map[Value("e")] = Value("E"); + // The empty string is shorter than all others, so should appear first among + // the strings. + map[Value("")] = Value("."); + // Map keys are sorted by major type, by byte length, and then by + // byte-wise lexical order. So all integer type keys should appear before + // key "" and all positive integer keys should appear before negative integer + // keys. + map[Value(-1)] = Value("k"); + map[Value(-24)] = Value("l"); + map[Value(-25)] = Value("m"); + map[Value(-256)] = Value("n"); + map[Value(-257)] = Value("o"); + map[Value(-65537)] = Value("p"); + map[Value(int64_t(-4294967296))] = Value("q"); + map[Value(int64_t(-4294967297))] = Value("r"); + map[Value(std::numeric_limits::min())] = Value("s"); + map[Value(Value::BinaryValue{'a'})] = Value(2); + map[Value(Value::BinaryValue{'b', 'a', 'r'})] = Value(3); + map[Value(Value::BinaryValue{'f', 'o', 'o'})] = Value(4); + map[Value(0)] = Value("a"); + map[Value(23)] = Value("b"); + map[Value(24)] = Value("c"); + map[Value(std::numeric_limits::max())] = Value("d"); + map[Value(256)] = Value("e"); + map[Value(std::numeric_limits::max())] = Value("f"); + map[Value(65536)] = Value("g"); + map[Value(int64_t(std::numeric_limits::max()))] = Value("h"); + map[Value(int64_t(4294967296))] = Value("i"); + map[Value(std::numeric_limits::max())] = Value("j"); + auto cbor = Writer::Write(Value(map)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), testing::ElementsAreArray( + kMapTestCaseCbor, arraysize(kMapTestCaseCbor))); +} + +TEST(CBORWriterTest, TestWriteMapWithArray) { + static const uint8_t kMapArrayTestCaseCbor[] = { + // clang-format off + 0xa2, // map of 2 pairs + 0x61, 0x61, // "a" + 0x01, + + 0x61, 0x62, // "b" + 0x82, // array with 2 elements + 0x02, + 0x03, + // clang-format on + }; + Value::MapValue map; + map[Value("a")] = Value(1); + Value::ArrayValue array; + array.push_back(Value(2)); + array.push_back(Value(3)); + map[Value("b")] = Value(array); + auto cbor = Writer::Write(Value(map)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), + testing::ElementsAreArray(kMapArrayTestCaseCbor, + arraysize(kMapArrayTestCaseCbor))); +} + +TEST(CBORWriterTest, TestWriteNestedMap) { + static const uint8_t kNestedMapTestCase[] = { + // clang-format off + 0xa2, // map of 2 pairs + 0x61, 0x61, // "a" + 0x01, + + 0x61, 0x62, // "b" + 0xa2, // map of 2 pairs + 0x61, 0x63, // "c" + 0x02, + + 0x61, 0x64, // "d" + 0x03, + // clang-format on + }; + Value::MapValue map; + map[Value("a")] = Value(1); + Value::MapValue nested_map; + nested_map[Value("c")] = Value(2); + nested_map[Value("d")] = Value(3); + map[Value("b")] = Value(nested_map); + auto cbor = Writer::Write(Value(map)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), + testing::ElementsAreArray(kNestedMapTestCase, + arraysize(kNestedMapTestCase))); +} + +TEST(CBORWriterTest, TestSignedExchangeExample) { + // Example adopted from: + // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html + static const uint8_t kSignedExchangeExample[] = { + // clang-format off + 0xa5, // map of 5 pairs + 0x0a, // 10 + 0x01, + + 0x18, 0x64, // 100 + 0x02, + + 0x20, // -1 + 0x03, + + 0x61, 'z', // text string "z" + 0x04, + + 0x62, 'a', 'a', // text string "aa" + 0x05, + + /* + 0x81, 0x18, 0x64, // [100] (array as map key is not yet supported) + 0x06, + + 0x81, 0x20, // [-1] (array as map key is not yet supported) + 0x07, + + 0xf4, // false (boolean as map key is not yet supported) + 0x08, + */ + // clang-format on + }; + Value::MapValue map; + map[Value(10)] = Value(1); + map[Value(100)] = Value(2); + map[Value(-1)] = Value(3); + map[Value("z")] = Value(4); + map[Value("aa")] = Value(5); + + auto cbor = Writer::Write(Value(map)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), + testing::ElementsAreArray(kSignedExchangeExample, + arraysize(kSignedExchangeExample))); +} + +TEST(CBORWriterTest, TestWriteSimpleValue) { + static const struct { + Value::SimpleValue simple_value; + const base::StringPiece cbor; + } kSimpleTestCase[] = { + {Value::SimpleValue::FALSE_VALUE, base::StringPiece("\xf4")}, + {Value::SimpleValue::TRUE_VALUE, base::StringPiece("\xf5")}, + {Value::SimpleValue::NULL_VALUE, base::StringPiece("\xf6")}, + {Value::SimpleValue::UNDEFINED, base::StringPiece("\xf7")}}; + + for (const auto& test_case : kSimpleTestCase) { + auto cbor = Writer::Write(Value(test_case.simple_value)); + ASSERT_TRUE(cbor.has_value()); + EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor)); + } +} + +// For major type 0, 2, 3, empty CBOR array, and empty CBOR map, the nesting +// depth is expected to be 0 since the CBOR decoder does not need to parse +// any nested CBOR value elements. +TEST(CBORWriterTest, TestWriteSingleLayer) { + const Value simple_uint = Value(1); + const Value simple_string = Value("a"); + const std::vector byte_data = {0x01, 0x02, 0x03, 0x04}; + const Value simple_bytestring = Value(byte_data); + Value::ArrayValue empty_cbor_array; + Value::MapValue empty_cbor_map; + const Value empty_array_value = Value(empty_cbor_array); + const Value empty_map_value = Value(empty_cbor_map); + Value::ArrayValue simple_array; + simple_array.push_back(Value(2)); + Value::MapValue simple_map; + simple_map[Value("b")] = Value(3); + const Value single_layer_cbor_map = Value(simple_map); + const Value single_layer_cbor_array = Value(simple_array); + + EXPECT_TRUE(Writer::Write(simple_uint, 0).has_value()); + EXPECT_TRUE(Writer::Write(simple_string, 0).has_value()); + EXPECT_TRUE(Writer::Write(simple_bytestring, 0).has_value()); + + EXPECT_TRUE(Writer::Write(empty_array_value, 0).has_value()); + EXPECT_TRUE(Writer::Write(empty_map_value, 0).has_value()); + + EXPECT_FALSE(Writer::Write(single_layer_cbor_array, 0).has_value()); + EXPECT_TRUE(Writer::Write(single_layer_cbor_array, 1).has_value()); + + EXPECT_FALSE(Writer::Write(single_layer_cbor_map, 0).has_value()); + EXPECT_TRUE(Writer::Write(single_layer_cbor_map, 1).has_value()); +} + +// Major type 5 nested CBOR map value with following structure. +// {"a": 1, +// "b": {"c": 2, +// "d": 3}} +TEST(CBORWriterTest, NestedMaps) { + Value::MapValue cbor_map; + cbor_map[Value("a")] = Value(1); + Value::MapValue nested_map; + nested_map[Value("c")] = Value(2); + nested_map[Value("d")] = Value(3); + cbor_map[Value("b")] = Value(nested_map); + EXPECT_TRUE(Writer::Write(Value(cbor_map), 2).has_value()); + EXPECT_FALSE(Writer::Write(Value(cbor_map), 1).has_value()); +} + +// Testing Write() function for following CBOR structure with depth of 3. +// [1, +// 2, +// 3, +// {"a": 1, +// "b": {"c": 2, +// "d": 3}}] +TEST(CBORWriterTest, UnbalancedNestedContainers) { + Value::ArrayValue cbor_array; + Value::MapValue cbor_map; + Value::MapValue nested_map; + + cbor_map[Value("a")] = Value(1); + nested_map[Value("c")] = Value(2); + nested_map[Value("d")] = Value(3); + cbor_map[Value("b")] = Value(nested_map); + cbor_array.push_back(Value(1)); + cbor_array.push_back(Value(2)); + cbor_array.push_back(Value(3)); + cbor_array.push_back(Value(cbor_map)); + + EXPECT_TRUE(Writer::Write(Value(cbor_array), 3).has_value()); + EXPECT_FALSE(Writer::Write(Value(cbor_array), 2).has_value()); +} + +// Testing Write() function for following CBOR structure. +// {"a": 1, +// "b": {"c": 2, +// "d": 3 +// "h": { "e": 4, +// "f": 5, +// "g": [6, 7, [8]]}}} +// Since above CBOR contains 5 nesting levels. Thus, Write() is expected to +// return empty optional object when maximum nesting layer size is set to 4. +TEST(CBORWriterTest, OverlyNestedCBOR) { + Value::MapValue map; + Value::MapValue nested_map; + Value::MapValue inner_nested_map; + Value::ArrayValue inner_array; + Value::ArrayValue array; + + map[Value("a")] = Value(1); + nested_map[Value("c")] = Value(2); + nested_map[Value("d")] = Value(3); + inner_nested_map[Value("e")] = Value(4); + inner_nested_map[Value("f")] = Value(5); + inner_array.push_back(Value(6)); + array.push_back(Value(6)); + array.push_back(Value(7)); + array.push_back(Value(inner_array)); + inner_nested_map[Value("g")] = Value(array); + nested_map[Value("h")] = Value(inner_nested_map); + map[Value("b")] = Value(nested_map); + + EXPECT_TRUE(Writer::Write(Value(map), 5).has_value()); + EXPECT_FALSE(Writer::Write(Value(map), 4).has_value()); +} + +} // namespace cbor -- cgit v1.2.1