diff options
Diffstat (limited to 'third_party/rust/moz_cbor')
-rw-r--r-- | third_party/rust/moz_cbor/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/Cargo.toml | 23 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/LICENSE | 373 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/README.md | 8 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/rustfmt.toml | 0 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/src/decoder.rs | 165 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/src/lib.rs | 51 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/src/serializer.rs | 124 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/src/test_decoder.rs | 445 | ||||
-rw-r--r-- | third_party/rust/moz_cbor/src/test_serializer.rs | 324 |
10 files changed, 1514 insertions, 0 deletions
diff --git a/third_party/rust/moz_cbor/.cargo-checksum.json b/third_party/rust/moz_cbor/.cargo-checksum.json new file mode 100644 index 0000000000..e3c215583d --- /dev/null +++ b/third_party/rust/moz_cbor/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"137eb0326df095bf3fa030839b880f2cf4f370a44511effc4c2a4760798bc695","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"900075da16923e46236926014f2ce8a0a404dfcedceee43d9ad50e6202ab1184","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/decoder.rs":"979a2165a0452368a0eba1da9066ed4cca491567b087dc051f4e65d15a6f13fa","src/lib.rs":"e8b91d719c9ab39562cc101c1fddd1953f7a119ce73320432a4b2647c92b2886","src/serializer.rs":"5e0466556ddc5e222339f244967f10549eb215b5d82ceb655e1838918212bde7","src/test_decoder.rs":"882b804096647cf3864ba067ef3d6eaca60e7945924ca4f122a3bd67a89f298d","src/test_serializer.rs":"b1c198ebc423849504333439c00a5c30dd40a5965da56dd32cc1be5d29d9cb15"},"package":"2133b12230591b7e727c8977b96b791bba421cd80ce8eb08b782dcb4a43fa1e9"}
\ No newline at end of file diff --git a/third_party/rust/moz_cbor/Cargo.toml b/third_party/rust/moz_cbor/Cargo.toml new file mode 100644 index 0000000000..e849e919ad --- /dev/null +++ b/third_party/rust/moz_cbor/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "moz_cbor" +version = "0.1.2" +authors = ["Franziskus Kiefer <franziskuskiefer@gmail.com>", "David Keeler <dkeeler@mozilla.com>"] +description = "Library to use CBOR (https://tools.ietf.org/html/rfc7049) in Rust" +keywords = ["jose", "cbor"] +license = "MPL-2.0" +repository = "https://github.com/franziskuskiefer/cbor-rust" + +[features] +default = [] diff --git a/third_party/rust/moz_cbor/LICENSE b/third_party/rust/moz_cbor/LICENSE new file mode 100644 index 0000000000..a612ad9813 --- /dev/null +++ b/third_party/rust/moz_cbor/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/third_party/rust/moz_cbor/README.md b/third_party/rust/moz_cbor/README.md new file mode 100644 index 0000000000..5b8da92e6c --- /dev/null +++ b/third_party/rust/moz_cbor/README.md @@ -0,0 +1,8 @@ +# cbor-rust + +A Rust library for [CBOR](https://tools.ietf.org/html/rfc7049). + +[![Build Status](https://travis-ci.org/franziskuskiefer/cbor-rust.svg?branch=master)](https://travis-ci.org/franziskuskiefer/cbor-rust/) +![Maturity Level](https://img.shields.io/badge/maturity-alpha-red.svg) + +**THIS IS WORK IN PROGRESS. DO NOT USE YET.** diff --git a/third_party/rust/moz_cbor/rustfmt.toml b/third_party/rust/moz_cbor/rustfmt.toml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/third_party/rust/moz_cbor/rustfmt.toml diff --git a/third_party/rust/moz_cbor/src/decoder.rs b/third_party/rust/moz_cbor/src/decoder.rs new file mode 100644 index 0000000000..f93bb13f1c --- /dev/null +++ b/third_party/rust/moz_cbor/src/decoder.rs @@ -0,0 +1,165 @@ +use std::collections::BTreeMap; +use std::io::{Cursor, Read, Seek, SeekFrom}; +use {CborError, CborType}; + +// We limit the length of any cbor byte array to 128MiB. This is a somewhat +// arbitrary limit that should work on all platforms and is large enough for +// any benign data. +pub const MAX_ARRAY_SIZE: usize = 134_217_728; + +// Prevent stack exhaustion by limiting the nested depth of CBOR data. +const MAX_NESTED_DEPTH: usize = 256; + +/// Struct holding a cursor and additional information for decoding. +#[derive(Debug)] +struct DecoderCursor<'a> { + cursor: Cursor<&'a [u8]>, + depth: usize, +} + +/// Apply this mask (with &) to get the value part of the initial byte of a CBOR item. +const INITIAL_VALUE_MASK: u64 = 0b0001_1111; + +impl<'a> DecoderCursor<'a> { + /// Read and return the given number of bytes from the cursor. Advances the cursor. + fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, CborError> { + if len > MAX_ARRAY_SIZE { + return Err(CborError::InputTooLarge); + } + let mut buf: Vec<u8> = vec![0; len]; + if self.cursor.read_exact(&mut buf).is_err() { + Err(CborError::TruncatedInput) + } else { + Ok(buf) + } + } + + /// Convert num bytes to a u64 + fn read_uint_from_bytes(&mut self, num: usize) -> Result<u64, CborError> { + let x = self.read_bytes(num)?; + let mut result: u64 = 0; + for i in (0..num).rev() { + result += u64::from(x[num - 1 - i]) << (i * 8); + } + Ok(result) + } + + /// Read an integer and return it as u64. + fn read_int(&mut self) -> Result<u64, CborError> { + let first_value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK; + match first_value { + 0..=23 => Ok(first_value), + 24 => self.read_uint_from_bytes(1), + 25 => self.read_uint_from_bytes(2), + 26 => self.read_uint_from_bytes(4), + 27 => self.read_uint_from_bytes(8), + _ => Err(CborError::MalformedInput), + } + } + + fn read_negative_int(&mut self) -> Result<CborType, CborError> { + let uint = self.read_int()?; + if uint > i64::max_value() as u64 { + return Err(CborError::InputValueOutOfRange); + } + let result: i64 = -1 - uint as i64; + Ok(CborType::SignedInteger(result)) + } + + /// Read an array of data items and return it. + fn read_array(&mut self) -> Result<CborType, CborError> { + // Create a new array. + let mut array: Vec<CborType> = Vec::new(); + // Read the length of the array. + let num_items = self.read_int()?; + // Decode each of the num_items data items. + for _ in 0..num_items { + let new_item = self.decode_item()?; + array.push(new_item); + } + Ok(CborType::Array(array)) + } + + /// Read a byte string and return it. + fn read_byte_string(&mut self) -> Result<CborType, CborError> { + let length = self.read_int()?; + if length > MAX_ARRAY_SIZE as u64 { + return Err(CborError::InputTooLarge); + } + let byte_string = self.read_bytes(length as usize)?; + Ok(CborType::Bytes(byte_string)) + } + + /// Read a map. + fn read_map(&mut self) -> Result<CborType, CborError> { + let num_items = self.read_int()?; + // Create a new array. + let mut map: BTreeMap<CborType, CborType> = BTreeMap::new(); + // Decode each of the num_items (key, data item) pairs. + for _ in 0..num_items { + let key_val = self.decode_item()?; + let item_value = self.decode_item()?; + if map.insert(key_val, item_value).is_some() { + return Err(CborError::DuplicateMapKey); + } + } + Ok(CborType::Map(map)) + } + + fn read_null(&mut self) -> Result<CborType, CborError> { + let value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK; + if value != 22 { + return Err(CborError::UnsupportedType); + } + Ok(CborType::Null) + } + + /// Peeks at the next byte in the cursor, but does not change the position. + fn peek_byte(&mut self) -> Result<u8, CborError> { + let x = self.read_bytes(1)?; + if self.cursor.seek(SeekFrom::Current(-1)).is_err() { + return Err(CborError::LibraryError); + }; + Ok(x[0]) + } + + /// Decodes the next CBOR item. + pub fn decode_item(&mut self) -> Result<CborType, CborError> { + if self.depth > MAX_NESTED_DEPTH { + return Err(CborError::MalformedInput); + } + self.depth += 1; + let major_type = self.peek_byte()? >> 5; + let result = match major_type { + 0 => { + let value = self.read_int()?; + Ok(CborType::Integer(value)) + } + 1 => self.read_negative_int(), + 2 => self.read_byte_string(), + 4 => self.read_array(), + 5 => self.read_map(), + 6 => { + let tag = self.read_int()?; + let item = self.decode_item()?; + Ok(CborType::Tag(tag, Box::new(item))) + } + 7 => self.read_null(), + _ => Err(CborError::UnsupportedType), + }; + self.depth -= 1; + result + } +} + +/// Read the CBOR structure in bytes and return it as a `CborType`. To prevent stack exhaustion, the +/// maximum nested depth of CBOR objects (for example, an array of an array of an array...) is 256. +/// If the input data describes a CBOR structure that exceeds this limit, an error will be returned. +pub fn decode(bytes: &[u8]) -> Result<CborType, CborError> { + let mut decoder_cursor = DecoderCursor { + cursor: Cursor::new(bytes), + depth: 0, + }; + decoder_cursor.decode_item() + // TODO: check cursor at end? +} diff --git a/third_party/rust/moz_cbor/src/lib.rs b/third_party/rust/moz_cbor/src/lib.rs new file mode 100644 index 0000000000..de9f992df0 --- /dev/null +++ b/third_party/rust/moz_cbor/src/lib.rs @@ -0,0 +1,51 @@ +pub mod decoder; +pub mod serializer; +#[cfg(test)] +mod test_decoder; +#[cfg(test)] +mod test_serializer; + +use std::cmp::Ordering; +use std::collections::BTreeMap; + +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq)] +pub enum CborType { + Integer(u64), + SignedInteger(i64), + Tag(u64, Box<CborType>), + Bytes(Vec<u8>), + String(String), + Array(Vec<CborType>), + Map(BTreeMap<CborType, CborType>), + Null, +} + +#[derive(Debug, PartialEq)] +pub enum CborError { + DuplicateMapKey, + InputTooLarge, + InputValueOutOfRange, + LibraryError, + MalformedInput, + TruncatedInput, + UnsupportedType, +} + +impl Ord for CborType { + /// Sorting for maps: RFC 7049 Section 3.9 + /// + /// The keys in every map must be sorted lowest value to highest. + /// * 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. + fn cmp(&self, other: &Self) -> Ordering { + let self_bytes = self.serialize(); + let other_bytes = other.serialize(); + if self_bytes.len() == other_bytes.len() { + return self_bytes.cmp(&other_bytes); + } + self_bytes.len().cmp(&other_bytes.len()) + } +} diff --git a/third_party/rust/moz_cbor/src/serializer.rs b/third_party/rust/moz_cbor/src/serializer.rs new file mode 100644 index 0000000000..b796aaedc7 --- /dev/null +++ b/third_party/rust/moz_cbor/src/serializer.rs @@ -0,0 +1,124 @@ +use std::collections::BTreeMap; +use CborType; + +/// Given a vector of bytes to append to, a tag to use, and an unsigned value to encode, uses the +/// CBOR unsigned integer encoding to represent the given value. +fn common_encode_unsigned(output: &mut Vec<u8>, tag: u8, value: u64) { + assert!(tag < 8); + let shifted_tag = tag << 5; + match value { + 0..=23 => { + output.push(shifted_tag | (value as u8)); + } + 24..=255 => { + output.push(shifted_tag | 24); + output.push(value as u8); + } + 256..=65_535 => { + output.push(shifted_tag | 25); + output.push((value >> 8) as u8); + output.push((value & 255) as u8); + } + 65_536..=4_294_967_295 => { + output.push(shifted_tag | 26); + output.push((value >> 24) as u8); + output.push(((value >> 16) & 255) as u8); + output.push(((value >> 8) & 255) as u8); + output.push((value & 255) as u8); + } + _ => { + output.push(shifted_tag | 27); + output.push((value >> 56) as u8); + output.push(((value >> 48) & 255) as u8); + output.push(((value >> 40) & 255) as u8); + output.push(((value >> 32) & 255) as u8); + output.push(((value >> 24) & 255) as u8); + output.push(((value >> 16) & 255) as u8); + output.push(((value >> 8) & 255) as u8); + output.push((value & 255) as u8); + } + }; +} + +/// The major type is 0. For values 0 through 23, the 5 bits of additional information is just the +/// value of the unsigned number. For values representable in one byte, the additional information +/// has the value 24. If two bytes are necessary, the value is 25. If four bytes are necessary, the +/// value is 26. If 8 bytes are necessary, the value is 27. The following bytes are the value of the +/// unsigned number in as many bytes were indicated in network byte order (big endian). +fn encode_unsigned(output: &mut Vec<u8>, unsigned: u64) { + common_encode_unsigned(output, 0, unsigned); +} + +/// The major type is 1. The encoding is the same as for positive (i.e. unsigned) integers, except +/// the value encoded is -1 minus the value of the negative number. +fn encode_negative(output: &mut Vec<u8>, negative: i64) { + assert!(negative < 0); + let value_to_encode: u64 = (-1 - negative) as u64; + common_encode_unsigned(output, 1, value_to_encode); +} + +/// The major type is 2. The length of the data is encoded as with positive integers, followed by +/// the actual data. +fn encode_bytes(output: &mut Vec<u8>, bstr: &[u8]) { + common_encode_unsigned(output, 2, bstr.len() as u64); + output.extend_from_slice(bstr); +} + +/// The major type is 3. The length is as with bstr. The UTF-8-encoded bytes of the string follow. +fn encode_string(output: &mut Vec<u8>, tstr: &str) { + let utf8_bytes = tstr.as_bytes(); + common_encode_unsigned(output, 3, utf8_bytes.len() as u64); + output.extend_from_slice(utf8_bytes); +} + +/// The major type is 4. The number of items is encoded as with positive integers. Then follows the +/// encodings of the items themselves. +fn encode_array(output: &mut Vec<u8>, array: &[CborType]) { + common_encode_unsigned(output, 4, array.len() as u64); + for element in array { + output.append(&mut element.serialize()); + } +} + +/// The major type is 5. The number of pairs is encoded as with positive integers. Then follows the +/// encodings of each key, value pair. In Canonical CBOR, the keys must be sorted lowest value to +/// highest. +fn encode_map(output: &mut Vec<u8>, map: &BTreeMap<CborType, CborType>) { + common_encode_unsigned(output, 5, map.len() as u64); + for (key, value) in map { + output.append(&mut key.serialize()); + output.append(&mut value.serialize()); + } +} + +fn encode_tag(output: &mut Vec<u8>, tag: &u64, val: &CborType) { + common_encode_unsigned(output, 6, *tag); + output.append(&mut val.serialize()); +} + +/// The major type is 7. The only supported value for this type is 22, which is Null. +/// This makes the encoded value 246, or 0xf6. +fn encode_null(output: &mut Vec<u8>) { + output.push(0xf6); +} + +impl CborType { + /// Serialize a Cbor object. NB: if the object to be serialized consists of too many nested + /// Cbor objects (for example, Array(Array(Array(...(Array(0))))), it is possible that calling + /// serialize will exhaust the stack. It is considered the caller's responsibility to prevent + /// this. + pub fn serialize(&self) -> Vec<u8> { + let mut bytes: Vec<u8> = Vec::new(); + match *self { + CborType::Integer(ref unsigned) => encode_unsigned(&mut bytes, *unsigned), + CborType::SignedInteger(ref negative) => encode_negative(&mut bytes, *negative), + CborType::Bytes(ref bstr) => encode_bytes(&mut bytes, bstr), + CborType::String(ref tstr) => encode_string(&mut bytes, tstr), + CborType::Array(ref arr) => encode_array(&mut bytes, arr), + CborType::Map(ref map) => encode_map(&mut bytes, map), + CborType::Tag(ref t, ref val) => encode_tag(&mut bytes, t, val), + CborType::Null => encode_null(&mut bytes), + }; + bytes + } +} diff --git a/third_party/rust/moz_cbor/src/test_decoder.rs b/third_party/rust/moz_cbor/src/test_decoder.rs new file mode 100644 index 0000000000..68db8724d9 --- /dev/null +++ b/third_party/rust/moz_cbor/src/test_decoder.rs @@ -0,0 +1,445 @@ +use decoder::{decode, MAX_ARRAY_SIZE}; +use std::collections::BTreeMap; +use {CborError, CborType}; + +// First test all the basic types +fn test_decoder(bytes: Vec<u8>, expected: CborType) { + let result = decode(&bytes); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), expected); +} + +fn test_decoder_error(bytes: Vec<u8>, expected_error: CborError) { + let result = decode(&bytes); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), expected_error); +} + +fn test_integer(bytes: Vec<u8>, expected: u64) { + let decoded = decode(&bytes).unwrap(); + match decoded { + CborType::Integer(val) => assert_eq!(val, expected), + _ => assert_eq!(1, 0), + } +} + +fn test_integer_all(bytes: Vec<u8>, expected_value: u64) { + let expected = CborType::Integer(expected_value); + test_decoder(bytes.clone(), expected); + test_integer(bytes, expected_value); +} + +#[test] +fn test_integer_objects() { + let bytes: Vec<u8> = vec![0x00]; + test_integer_all(bytes, 0); + + let bytes = vec![0x01]; + test_integer_all(bytes, 1); + + let bytes = vec![0x0A]; + test_integer_all(bytes, 10); + + let bytes = vec![0x17]; + test_integer_all(bytes, 23); + + let bytes = vec![0x18, 0x18]; + test_integer_all(bytes, 24); + + let bytes = vec![0x18, 0x19]; + test_integer_all(bytes, 25); + + let bytes = vec![0x18, 0x64]; + test_integer_all(bytes, 100); + + let bytes = vec![0x19, 0x03, 0xe8]; + test_integer_all(bytes, 1000); + + let bytes = vec![0x1a, 0x00, 0x0f, 0x42, 0x40]; + test_integer_all(bytes, 1000000); + + let bytes = vec![0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00]; + test_integer_all(bytes, 1000000000000); + + let bytes = vec![0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; + test_integer_all(bytes, 18446744073709551615); +} + +#[cfg(test)] +fn test_tag(bytes: Vec<u8>, expected_tag: u64, expected_value: CborType) { + let decoded = decode(&bytes).unwrap(); + match decoded { + CborType::Tag(tag, value) => { + assert_eq!(expected_tag, tag); + assert_eq!(expected_value, *value); + } + _ => assert_eq!(1, 0), + } +} + +#[test] +fn test_tagged_objects() { + let bytes: Vec<u8> = vec![0xD2, 0x02]; + let expected_tag_value = 0x12; + let expected_value = CborType::Integer(2); + let expected = CborType::Tag(expected_tag_value, Box::new(expected_value.clone())); + test_decoder(bytes.clone(), expected); + test_tag(bytes, expected_tag_value, expected_value); +} + +#[test] +#[cfg_attr(rustfmt, rustfmt_skip)] +fn test_arrays() { + // [] + let bytes: Vec<u8> = vec![0x80]; + let expected = CborType::Array(vec![]); + test_decoder(bytes, expected); + + // [1, 2, 3] + let bytes: Vec<u8> = vec![0x83, 0x01, 0x02, 0x03]; + let tmp = vec![ + CborType::Integer(1), + CborType::Integer(2), + CborType::Integer(3), + ]; + let expected = CborType::Array(tmp); + test_decoder(bytes, expected); + + // [1, [2, 3], [4, 5]] + let bytes: Vec<u8> = vec![0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05]; + let tmp1 = vec![CborType::Integer(2), CborType::Integer(3)]; + let tmp2 = vec![CborType::Integer(4), CborType::Integer(5)]; + let tmp = vec![ + CborType::Integer(1), + CborType::Array(tmp1), + CborType::Array(tmp2), + ]; + let expected = CborType::Array(tmp); + test_decoder(bytes, expected); + + // [1, [[[[1]]]], [1]] + let bytes: Vec<u8> = vec![0x83, 0x01, 0x81, 0x81, 0x81, 0x81, 0x01, 0x81, 0x02]; + let tmp = vec![ + CborType::Integer(1), + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Integer(1)])])])]), + CborType::Array(vec![CborType::Integer(2)]), + ]; + let expected = CborType::Array(tmp); + test_decoder(bytes, expected); + + let bytes: Vec<u8> = vec![0x98, 0x1A, 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, 0x82, 0x81, 0x81, + 0x81, 0x05, 0x81, 0x1A, 0x49, 0x96, 0x02, 0xD2]; + // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + // 21, 22, 23, 24, 25, [[[[5]]], [1234567890]]] + let tmp = vec![ + CborType::Integer(1), + CborType::Integer(2), + CborType::Integer(3), + CborType::Integer(4), + CborType::Integer(5), + CborType::Integer(6), + CborType::Integer(7), + CborType::Integer(8), + CborType::Integer(9), + CborType::Integer(10), + CborType::Integer(11), + CborType::Integer(12), + CborType::Integer(13), + CborType::Integer(14), + CborType::Integer(15), + CborType::Integer(16), + CborType::Integer(17), + CborType::Integer(18), + CborType::Integer(19), + CborType::Integer(20), + CborType::Integer(21), + CborType::Integer(22), + CborType::Integer(23), + CborType::Integer(24), + CborType::Integer(25), + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Array(vec![ + CborType::Integer(5)])])]), + CborType::Array(vec![CborType::Integer(1234567890)])]) + ]; + let expected = CborType::Array(tmp); + test_decoder(bytes, expected); +} + +#[test] +fn test_signed_integer() { + let bytes: Vec<u8> = vec![0x20]; + let expected = CborType::SignedInteger(-1); + test_decoder(bytes, expected); + + let bytes = vec![0x29]; + let expected = CborType::SignedInteger(-10); + test_decoder(bytes, expected); + + let bytes = vec![0x38, 0x63]; + let expected = CborType::SignedInteger(-100); + test_decoder(bytes, expected); + + let bytes = vec![0x39, 0x03, 0xe7]; + let expected = CborType::SignedInteger(-1000); + test_decoder(bytes, expected); + + let bytes = vec![0x39, 0x27, 0x0F]; + let expected = CborType::SignedInteger(-10000); + test_decoder(bytes, expected); + + let bytes = vec![0x3A, 0x00, 0x01, 0x86, 0x9F]; + let expected = CborType::SignedInteger(-100000); + test_decoder(bytes, expected); + + let bytes = vec![0x3B, 0x00, 0x00, 0x00, 0xE8, 0xD4, 0xA5, 0x0F, 0xFF]; + let expected = CborType::SignedInteger(-1000000000000); + test_decoder(bytes, expected); +} + +#[test] +fn test_byte_strings() { + let bytes: Vec<u8> = vec![0x40]; + let expected = CborType::Bytes(vec![]); + test_decoder(bytes, expected); + + // 01020304 + let bytes: Vec<u8> = vec![0x44, 0x01, 0x02, 0x03, 0x04]; + let expected = CborType::Bytes(vec![0x01, 0x02, 0x03, 0x04]); + test_decoder(bytes, expected); + + // 0102030405060708090A0B0C0D0E0F10203040506070 + let bytes: Vec<u8> = vec![ + 0x56, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + ]; + let expected = CborType::Bytes(vec![ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + ]); + test_decoder(bytes, expected); + + let bytes: Vec<u8> = vec![ + 0x59, 0x01, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + ]; + let expected = CborType::Bytes(vec![ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + ]); + test_decoder(bytes, expected); +} + +#[test] +fn test_maps() { + // {} + let bytes: Vec<u8> = vec![0xa0]; + let expected: BTreeMap<CborType, CborType> = BTreeMap::new(); + test_decoder(bytes, CborType::Map(expected)); + + // {1: 2, 3: 4} + let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x03, 0x04]; + let mut expected: BTreeMap<CborType, CborType> = BTreeMap::new(); + expected.insert(CborType::Integer(1), CborType::Integer(2)); + expected.insert(CborType::Integer(3), CborType::Integer(4)); + test_decoder(bytes, CborType::Map(expected)); + + // TODO: strings aren't properly supported as keys yet. + // {"a": 1, "b": [2, 3]} + // let bytes: Vec<u8> = vec![0xa2, 0x61, 0x61, 0x01, 0x61, 0x62, 0x82, 0x02, 0x03]; + // let expected = + // CborType::Map(vec![ + // CborMap{key: CborType::Integer(1), value: CborType::Integer(2)}, + // CborMap{key: CborType::Integer(3), value: CborType::Integer(4)}]); + // test_decoder(bytes, expected); + + // let bytes: Vec<u8> = vec![0x82, 0x61, 0x61, 0xa1, 0x61, 0x62, 0x61, 0x63]; + // test_decoder(bytes, "[a, {b: c}]"); + + // let bytes: Vec<u8> = vec![0xa5, 0x61, 0x61, 0x61, 0x41, 0x61, 0x62, 0x61, + // 0x42, 0x61, 0x63, 0x61, 0x43, 0x61, 0x64, 0x61, + // 0x44, 0x61, 0x65, 0x61, 0x45]; + // test_decoder(bytes, "{a: A, b: B, c: C, d: D, e: E}"); +} + +#[test] +fn test_map_duplicate_keys() { + let bytes: Vec<u8> = vec![0xa4, 0x01, 0x02, 0x02, 0x03, 0x01, 0x03, 0x04, 0x04]; + test_decoder_error(bytes, CborError::DuplicateMapKey); +} + +#[test] +fn test_tag_with_no_value() { + let bytes: Vec<u8> = vec![0xc0]; + test_decoder_error(bytes, CborError::TruncatedInput); +} + +#[test] +fn test_truncated_int() { + let bytes: Vec<u8> = vec![0x19, 0x03]; + test_decoder_error(bytes, CborError::TruncatedInput); +} + +#[test] +fn test_truncated_array() { + let bytes: Vec<u8> = vec![0x83, 0x01, 0x02]; + test_decoder_error(bytes, CborError::TruncatedInput); +} + +#[test] +fn test_truncated_map() { + let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x00]; + test_decoder_error(bytes, CborError::TruncatedInput); +} + +#[test] +fn test_malformed_integer() { + let bytes: Vec<u8> = vec![0x1c]; + test_decoder_error(bytes, CborError::MalformedInput); +} + +#[test] +fn test_signed_integer_too_large() { + let bytes = vec![0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; + test_decoder_error(bytes, CborError::InputValueOutOfRange); +} + +#[test] +fn test_null() { + let bytes = vec![0xf6]; + test_decoder(bytes, CborType::Null); +} + +#[test] +fn test_null_in_array() { + let bytes = vec![0x82, 0xf6, 0xf6]; + test_decoder(bytes, CborType::Array(vec![CborType::Null, CborType::Null])); +} + +#[test] +fn test_major_type_7() { + for i in 0..0x20 { + if i != 22 { + let bytes = vec![0xe0 | i]; + test_decoder_error(bytes, CborError::UnsupportedType); + } + } +} + +#[test] +fn test_large_input() { + let array = vec![0xFF; MAX_ARRAY_SIZE]; + let expected = CborType::Bytes(array.clone()); + let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x00]; + bytes.extend_from_slice(&array); + test_decoder(bytes, expected); +} + +#[test] +fn test_too_large_input() { + let array = vec![0xFF; MAX_ARRAY_SIZE + 1]; + let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x01]; + bytes.extend_from_slice(&array); + test_decoder_error(bytes, CborError::InputTooLarge); +} + +// We currently don't support CBOR strings (issue #39). +#[test] +fn test_invalid_input() { + let bytes = vec![0x60]; + test_decoder_error(bytes, CborError::UnsupportedType); +} + +#[test] +fn test_avoid_stack_exhaustion_with_arrays() { + let mut bytes: Vec<u8> = Vec::new(); + // Create a payload representing Array(Array(Array(Array(...(Array(0)))))) + // If the implementation is not careful, this will exhaust the stack. + for _ in 1..10000 { + bytes.push(0b1000_0001); + } + bytes.push(0); + test_decoder_error(bytes, CborError::MalformedInput); +} + +#[test] +fn test_avoid_stack_exhaustion_with_maps_1() { + let mut bytes: Vec<u8> = Vec::new(); + // Create a payload representing Map(0: Map(0: Map(0: Map(...Map())))) + // If the implementation is not careful, this will exhaust the stack. + for _ in 1..10000 { + bytes.push(0b1010_0001); + bytes.push(0); + } + bytes.push(0b1010_0000); + test_decoder_error(bytes, CborError::MalformedInput); +} + +#[test] +fn test_avoid_stack_exhaustion_with_maps_2() { + let mut bytes: Vec<u8> = Vec::new(); + // Create a payload representing Map(Map(Map(...(Map(): 0): 0): 0): 0) + // If the implementation is not careful, this will exhaust the stack. + for _ in 1..10000 { + bytes.push(0b1010_0001); + } + bytes.push(0b1010_0000); + for _ in 1..9999 { + bytes.push(0); + } + test_decoder_error(bytes, CborError::MalformedInput); +} + +#[test] +fn test_avoid_stack_exhaustion_with_tags() { + let mut bytes: Vec<u8> = Vec::new(); + // Create a payload representing Tag(6: Tag(6: Tag(6: Tag(...Tag(0))))) + // If the implementation is not careful, this will exhaust the stack. + for _ in 1..10000 { + bytes.push(0b1100_0110); + } + bytes.push(0); + test_decoder_error(bytes, CborError::MalformedInput); +} diff --git a/third_party/rust/moz_cbor/src/test_serializer.rs b/third_party/rust/moz_cbor/src/test_serializer.rs new file mode 100644 index 0000000000..09800f5a50 --- /dev/null +++ b/third_party/rust/moz_cbor/src/test_serializer.rs @@ -0,0 +1,324 @@ +use std::collections::BTreeMap; +use CborType; + +#[test] +fn test_nint() { + struct Testcase { + value: i64, + expected: Vec<u8>, + } + let testcases: Vec<Testcase> = vec![ + Testcase { + value: -1, + expected: vec![0x20], + }, + Testcase { + value: -10, + expected: vec![0x29], + }, + Testcase { + value: -100, + expected: vec![0x38, 0x63], + }, + Testcase { + value: -1000, + expected: vec![0x39, 0x03, 0xe7], + }, + Testcase { + value: -1000000, + expected: vec![0x3a, 0x00, 0x0f, 0x42, 0x3f], + }, + Testcase { + value: -4611686018427387903, + expected: vec![0x3b, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe], + }, + ]; + for testcase in testcases { + let cbor = CborType::SignedInteger(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_bstr() { + struct Testcase { + value: Vec<u8>, + expected: Vec<u8>, + } + let testcases: Vec<Testcase> = vec![ + Testcase { + value: vec![], + expected: vec![0x40], + }, + Testcase { + value: vec![0x01, 0x02, 0x03, 0x04], + expected: vec![0x44, 0x01, 0x02, 0x03, 0x04], + }, + Testcase { + value: vec![ + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + ], + expected: vec![ + 0x58, 0x19, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + ], + }, + ]; + for testcase in testcases { + let cbor = CborType::Bytes(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_tstr() { + struct Testcase { + value: String, + expected: Vec<u8>, + } + let testcases: Vec<Testcase> = vec![ + Testcase { + value: String::new(), + expected: vec![0x60], + }, + Testcase { + value: String::from("a"), + expected: vec![0x61, 0x61], + }, + Testcase { + value: String::from("IETF"), + expected: vec![0x64, 0x49, 0x45, 0x54, 0x46], + }, + Testcase { + value: String::from("\"\\"), + expected: vec![0x62, 0x22, 0x5c], + }, + Testcase { + value: String::from("水"), + expected: vec![0x63, 0xe6, 0xb0, 0xb4], + }, + ]; + for testcase in testcases { + let cbor = CborType::String(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_arr() { + struct Testcase { + value: Vec<CborType>, + expected: Vec<u8>, + } + let nested_arr_1 = vec![CborType::Integer(2), CborType::Integer(3)]; + let nested_arr_2 = vec![CborType::Integer(4), CborType::Integer(5)]; + let testcases: Vec<Testcase> = vec![ + Testcase { + value: vec![], + expected: vec![0x80], + }, + Testcase { + value: vec![ + CborType::Integer(1), + CborType::Integer(2), + CborType::Integer(3), + ], + expected: vec![0x83, 0x01, 0x02, 0x03], + }, + Testcase { + value: vec![ + CborType::Integer(1), + CborType::Array(nested_arr_1), + CborType::Array(nested_arr_2), + ], + expected: vec![0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05], + }, + Testcase { + value: vec![ + CborType::Integer(1), + CborType::Integer(2), + CborType::Integer(3), + CborType::Integer(4), + CborType::Integer(5), + CborType::Integer(6), + CborType::Integer(7), + CborType::Integer(8), + CborType::Integer(9), + CborType::Integer(10), + CborType::Integer(11), + CborType::Integer(12), + CborType::Integer(13), + CborType::Integer(14), + CborType::Integer(15), + CborType::Integer(16), + CborType::Integer(17), + CborType::Integer(18), + CborType::Integer(19), + CborType::Integer(20), + CborType::Integer(21), + CborType::Integer(22), + CborType::Integer(23), + CborType::Integer(24), + CborType::Integer(25), + ], + expected: vec![ + 0x98, 0x19, 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, + ], + }, + ]; + for testcase in testcases { + let cbor = CborType::Array(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_map() { + let empty_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + assert_eq!(vec![0xa0], CborType::Map(empty_map).serialize()); + + let mut positive_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + positive_map.insert(CborType::Integer(20), CborType::Integer(10)); + positive_map.insert(CborType::Integer(10), CborType::Integer(20)); + positive_map.insert(CborType::Integer(15), CborType::Integer(15)); + assert_eq!( + vec![0xa3, 0x0a, 0x14, 0x0f, 0x0f, 0x14, 0x0a], + CborType::Map(positive_map).serialize() + ); + + let mut negative_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + negative_map.insert(CborType::SignedInteger(-4), CborType::Integer(10)); + negative_map.insert(CborType::SignedInteger(-1), CborType::Integer(20)); + negative_map.insert(CborType::SignedInteger(-5), CborType::Integer(15)); + negative_map.insert(CborType::SignedInteger(-6), CborType::Integer(10)); + assert_eq!( + vec![0xa4, 0x20, 0x14, 0x23, 0x0a, 0x24, 0x0f, 0x25, 0x0a], + CborType::Map(negative_map).serialize() + ); + + let mut mixed_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + mixed_map.insert(CborType::Integer(0), CborType::Integer(10)); + mixed_map.insert(CborType::SignedInteger(-10), CborType::Integer(20)); + mixed_map.insert(CborType::Integer(15), CborType::Integer(15)); + assert_eq!( + vec![0xa3, 0x00, 0x0a, 0x0f, 0x0f, 0x29, 0x14], + CborType::Map(mixed_map).serialize() + ); + + let mut very_mixed_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + very_mixed_map.insert(CborType::Integer(0), CborType::Integer(10)); + very_mixed_map.insert( + CborType::SignedInteger(-10000), + CborType::String("low".to_string()), + ); + very_mixed_map.insert(CborType::SignedInteger(-10), CborType::Integer(20)); + very_mixed_map.insert( + CborType::Integer(10001), + CborType::String("high".to_string()), + ); + very_mixed_map.insert( + CborType::Integer(10000), + CborType::String("high".to_string()), + ); + very_mixed_map.insert(CborType::Integer(15), CborType::Integer(15)); + let expected = vec![ + 0xa6, 0x00, 0x0a, 0x0f, 0x0f, 0x29, 0x14, 0x19, 0x27, 0x10, 0x64, 0x68, 0x69, 0x67, 0x68, + 0x19, 0x27, 0x11, 0x64, 0x68, 0x69, 0x67, 0x68, 0x39, 0x27, 0x0F, 0x63, 0x6C, 0x6F, 0x77, + ]; + assert_eq!(expected, CborType::Map(very_mixed_map).serialize()); +} + +#[test] +#[ignore] +// XXX: The string isn't put into the map at the moment, so we can't actually +// test this. +fn test_invalid_map() { + let mut invalid_map: BTreeMap<CborType, CborType> = BTreeMap::new(); + invalid_map.insert(CborType::SignedInteger(-10), CborType::Integer(20)); + invalid_map.insert(CborType::String("0".to_string()), CborType::Integer(10)); + invalid_map.insert(CborType::Integer(15), CborType::Integer(15)); + let expected: Vec<u8> = vec![]; + assert_eq!(expected, CborType::Map(invalid_map).serialize()); +} + +#[test] +fn test_integer() { + struct Testcase { + value: u64, + expected: Vec<u8>, + } + let testcases: Vec<Testcase> = vec![ + Testcase { + value: 0, + expected: vec![0], + }, + Testcase { + value: 1, + expected: vec![1], + }, + Testcase { + value: 10, + expected: vec![0x0a], + }, + Testcase { + value: 23, + expected: vec![0x17], + }, + Testcase { + value: 24, + expected: vec![0x18, 0x18], + }, + Testcase { + value: 25, + expected: vec![0x18, 0x19], + }, + Testcase { + value: 100, + expected: vec![0x18, 0x64], + }, + Testcase { + value: 1000, + expected: vec![0x19, 0x03, 0xe8], + }, + Testcase { + value: 1000000, + expected: vec![0x1a, 0x00, 0x0f, 0x42, 0x40], + }, + Testcase { + value: 1000000000000, + expected: vec![0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00], + }, + Testcase { + value: 18446744073709551615, + expected: vec![0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], + }, + ]; + for testcase in testcases { + let cbor = CborType::Integer(testcase.value); + assert_eq!(testcase.expected, cbor.serialize()); + } +} + +#[test] +fn test_tagged_item() { + let cbor = CborType::Tag(0x12, Box::new(CborType::Integer(2).clone())); + assert_eq!(vec![0xD2, 0x02], cbor.serialize()); + + let cbor = CborType::Tag(0x62, Box::new(CborType::Array(vec![]).clone())); + assert_eq!(vec![0xD8, 0x62, 0x80], cbor.serialize()); +} + +#[test] +fn test_null() { + let cbor = CborType::Null; + assert_eq!(vec![0xf6], cbor.serialize()); +} + +#[test] +fn test_null_in_array() { + let cbor = CborType::Array(vec![CborType::Null, CborType::Null]); + assert_eq!(vec![0x82, 0xf6, 0xf6], cbor.serialize()); +} |